如果我理解正确,我们至少有两种不同的方式来实现合成。 (为简单起见,排除了使用智能指针实现的情况。我几乎不使用STL,也不希望学习它。)
让我们来看看Wikipedia example:
class Car
{
private:
Carburetor* itsCarb;
public:
Car() {itsCarb=new Carburetor();}
virtual ~Car() {delete itsCarb;}
};
因此,这是一种方法-我们有一个指针将对象作为私有(private)成员。
可以将其重写为如下形式:
class Car
{
private:
Carburetor itsCarb;
};
在这种情况下,我们将对象本身作为私有(private)成员。 (顺便说一句,从术语的角度来看,我是否可以将此实体称为对象?)
在第二种情况下,没有必要隐式调用默认构造函数(如果需要调用非默认构造函数,则可以在初始值设定项列表中进行调用)和析构函数。但这不是大问题...
当然,在某些方面,这两种情况的区别更大。例如,在第二种情况下,禁止从Car类的const方法调用Carburetor实例的非const方法...
是否有任何“规则”来决定使用哪个?我想念什么吗?
最佳答案
是的,您可以说出该类的“对象”或“实例”。
您还可以谈论包含数据成员“按值”而不是“按指针”(因为“按指针”和“按值”是讨论传递参数的正常方法,因此我希望人们会理解所应用的那些术语)数据成员)。
如果实例由多个容器共享,则每个容器都应通过指针而不是值来包含该实例;例如,如果一个雇员有一个老板实例,如果几个雇员实例共享同一个老板,则按指针包括老板。
如果数据成员的生存期与容器的生存期不同,则通过指针将其包括在内:例如,数据成员是在容器之后实例化的,还是在容器之前被销毁的,或者在容器中被销毁并重新创建的容器的生存期,或者数据成员为null是否有意义。
另一个必须通过指针(或通过引用)而不是按值包括的时间是,数据成员的类型是抽象基类。
包含指针的另一个原因是,它可能允许您更改数据成员的实现而无需重新编译容器。例如,如果Car和Carburetor是在两个不同的DLL中定义的,则您可能希望通过指针包括Carburetor:因为这样,您可以通过安装其他Carburetor.dll
来更改Carburetor的实现,而无需重建Car.dll
。