2009-12-05 124 views
6

如果我理解正确,我们至少有两种不同的实现构图的方法。 (与智能指针实现的情况不为简单起见,我几乎不使用STL,没有欲望去学习它。)如何在C++中实现类组合?

让我们来看看维基百科example

class Car 
{ 
    private: 
    Carburetor* itsCarb; 
    public: 
    Car() {itsCarb=new Carburetor();} 
    virtual ~Car() {delete itsCarb;} 
}; 

所以,这是一种方法 - 我们有一个作为私人成员指向对象的指针。 我们可以把它改写成这样:

class Car 
{ 
    private: 
    Carburetor itsCarb; 
}; 

在这种情况下,我们有一个对象本身作为私有成员。 (顺便说一下,从术语的角度来看,我是否有权将这个实体称为对象?)

在第二种情况下,隐式调用默认构造函数不是强制性的(如果需要调用非默认构造函数可能在初始化列表中执行它)和析构函数。但它不是一个大问题...

当然,在某些方面,这两种情况的差异更明显。例如,禁止在第二种情况下从Car类的常量方法中调用化油器实例的非常量方法...

是否有任何“规则”来决定使用哪一个?我错过了什么吗?

+1

我想你的意思是“这是被禁止调用由Car类的常量方法化油器实例的非const方法”。 –

+0

@ Laurence Ooops。你当然是对的...... – Wildcat

+8

“[我]不想学习[STL]。”什么?通过忽略STL,你错过了C++的一大部分。 – rlbond

回答

7

在这种情况下,我们有一个对象本身作为私人成员。 (顺便说一下,从术语的角度来看,我称这个实体为对象吗?)

是的,你可以说类的“对象”或“实例”。你也可以谈论包括数据成员“按值”而不是“按指针”(因为“按指针”和“按值”是讨论传递参数的正常方法,所以我希望人们会理解这些条款适用于数据成员)。

是否有任何“规则”来决定使用哪一个?我错过了什么吗?

如果实例被多个容器共享,那么每个容器应该用指针而不是值包含它;例如,如果一个Employee有一个Boss实例,如果多个Employee实例共享相同的Boss,则通过指针包含Boss。

如果数据成员的生命周期与容器的生命周期不同,那么可以通过指针包含它:例如,如果数据成员在容器之后实例化,或者在容器之前销毁,并在容器的生命周期内重新创建,或者如果它对于数据成员为空是有意义的。

时,必须包含由指针(或通过引用)另一个时间,而不是由值是当所述数据成员的类型是一个抽象基类。

另一个原因,包括指针是,可能允许您更改数据成员的实现而无需重新编译的容器。例如,如果汽车和化油器在两个不同的DLL定义,你可能想通过指针包括化油器:因为这样你可能能够通过安装不同的Carburetor.dll改变化油器的实施,无需重建Car.dll

+0

+1,因为它们似乎迄今一直被忽视 – Glen

3

组成:如果可能,更喜欢成员。在需要多态性或使用前向声明时使用指针。当然,如果没有智能指针,当使用指针时需要手动内存管理。

1

如果Carb与Car有相同的生命周期,那么在我看来,非指针形式更好。如果您必须更换Carb Car,那么我会选择指针版本。

8

我倾向于更喜欢第一种情况,因为第二种情况要求您在Car.h中#include Carburettor.h。 由于Carburettor是一名私人成员,因此您不应该将其定义包含在实际的Car实现代码中。使用Carburettor类显然是一个实现细节,使用Car对象的外部对象不必担心包含其他非强制性依赖项。通过使用指针,你只需要在Car.h中使用Carburettor的前向声明。

+0

这两种情况都是一样的,所以我低估了这一点。 –

+0

你能更具体吗,林肯定你没有明白我的观点...... – nico

+2

这两种情况都不一样。正如nicolascormier指出的那样,您可以使用前向声明来避免包含头文件。也许你应该在downvoting之前了解答案。 –

0

一般来说,非指针的版本更容易使用和维护。

但在某些情况下,你不能使用它。例如,如果汽车有多个化油器,并且您希望将它们放在一个数组中,并且化油器构造函数需要参数:您需要通过new创建它们,并将它们存储为指针。