依赖类作为其他类成员

时间:2011-02-15 21:09:41

标签: c++ constructor initialization operator-precedence ctor-initializer

我有一个类B,需要构建一个类A的实例:

class B
{
    B(A* a); // there is no default constructor
};

现在我想创建一个包含B成员的类,所以我还需要添加A作为成员并将其提供给B的构造函数:

class C
{
    C() : a(), b(&a) {}
    A a; // 1. initialized as a()
    B b; // 2. initialized as b(&a) - OK
};

但问题是,如果有人偶尔更改类中变量 definition 的顺序,它将会中断

class C
{
    C() : a(), b(&a) {}
    B b; // 1. initialized as b(&a) while "a" uninitialized
    A a; // too late...
};

有没有一种很好的方法可以在不修改类AB的情况下解决这个问题?感谢。

6 个答案:

答案 0 :(得分:7)

  

有没有一种好方法可以在不修改A类和B类的情况下解决这个问题?

开启compiler warnings;对于gcc,这是-Wreorder(包含在-Wall中):

cc1plus: warnings being treated as errors
t.cpp: In constructor 'A::A()':
Line 3: warning: 'A::y' will be initialized after
Line 3: warning:   'int A::x'
Line 2: warning:   when initialized here

或者,使用类似lint的工具来检测它。


  

但问题是,如果有人偶尔改变类中变量定义的顺序......

他们为什么要这样做?我怀疑你太担心可能会发生什么。即便如此,您也可以在课堂上发表评论:

A a;  // Must be listed before member 'b'!
B b;

不要低估良好评论的力量。 :)然后允许有意无视他们的人获得他们应得的东西;毕竟你正在使用C ++。

答案 1 :(得分:5)

使用名为Base-from-Member的众所周知的C ++习语来解决这个问题。

将基类定义为

class C_Base
{
    A a; //moved `A a` to the base class!
    C_Base() : a() {}
};

class C : public C_Base
{
    C() : b(&a) {}
    B b; // 1. initialized as b(&a) while "a" uninitialized
    //A a; // too late...
};

现在,a保证在b之前初始化。

答案 2 :(得分:2)

将b存储在unique_ptr中,并将其设置在正文中,而不是在初始化列表中:

class C
{
    C() :a() {
        b = std::unique_ptr<B>(new B(&a));
    }
    A a;
    std::unique_ptr<B> b;
};

答案 3 :(得分:0)

一种选择是不显式存储A,而是使用动态分配来创建一个新的A来存储在B中:

class C {
public:
       C() : b(new A) {
           // handled in initialization list
       }
private:
       B b;
};

由于这可以保证在B之前创建A,因此可以防止此问题发生。

答案 4 :(得分:0)

问题是你用第三个例子射击自己。在C ++中,类/结构中成员变量的顺序很重要。无论你如何解决你的特定问题,如果由于糟糕的类设计/成员布局而将未初始化的数据传递给构造函数,你将使用单元化数据并可能获得未定义的行为,具体取决于所使用的代码类型。

要解决您的特定示例,如果B确实需要A且关系是一对一,为什么不创建一个同时具有{{1}的新类AB }对象和正确顺序的A对象,并将B的地址传递给A。那就是:

B

现在,通过使用class AB { public: AB():b_(&a_) {} private: A a_; B b_; }; 代替CAB,课程A可以避免排序问题:

B

如前所述,这当然假设class C { public: ... private: AB ab_; }; A之间存在1:1的关系。如果B对象可以被许多A个对象共享,那么事情会变得更加复杂。

答案 5 :(得分:0)

我不确定你对C的实现和结构有多少控制,但是有必要在C类中使用这些对象吗?您是否可以重新定义类以使用指针,然后将它们从初始化列表中移出,例如

class C
{
   C()
   {
     a = new A;
     b = new B(a);
   }
   ~C() {delete a; delete b;}

   A* a;
   B* b;
};

这样可以避免声明中的订单问题,但会为您提供确保正确创建订单的新问题。此外,如果您经常创建C的 A LOT ,初始化列表会稍快一些。