与其他类成员一样的依赖类

发布于 2024-10-17 23:18:47 字数 649 浏览 1 评论 0原文

我有一个类 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
};

但问题是,如果有人偶尔更改变量的顺序定义在类中,它会破坏

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

有没有一个好的方法可以解决这个问题而不修改类AB?谢谢。

I have a class B that requires an instance of class A to be constructed:

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

Now I want to create a class that contains B as a member, so I also need to add A as a member and provide it to B's constructor:

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

But the problem is that if someone occasionally changes the order of the variables definition in the class, it will break

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

Is there a good way to resolve this without modifying the classes A and B? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

香草可樂 2024-10-24 23:18:47

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

打开编译器警告;对于 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++。

Is there a good way to resolve this without modifying the classes A and B?

Turn on compiler warnings; for gcc, this is -Wreorder (which is included in -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

Alternatively, use a lint-like tool that detects this.


But the problem is that if someone occasionally changes the order of the variables definition in the class…

Why would they do this? I suspect you're worrying too much about what might happen. Even so, you can leave a comment in the class:

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

Don't underestimate the force of well-placed comments. :) Then allow someone who purposefully ignores them to get what they deserve; you are using C++, after all.

温柔一刀 2024-10-24 23:18:47

使用著名的 C++ 习惯用法 Base-from-Member 来解决这个问题。

将基类定义为,

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 之前初始化。

Use the well-known C++ idiom called Base-from-Member to solve this problem.

Define a base class as,

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...
};

Now, a is guaranteed to be initialized before b.

逆光下的微笑 2024-10-24 23:18:47

将 b 存储在 unique_ptr 中,并将其设置在主体中,而不是初始值设定项列表中:

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

Store b in a unique_ptr, and set it in the body, not in the initializer list:

class C
{
    C() :a() {
        b = std::unique_ptr<B>(new B(&a));
    }
    A a;
    std::unique_ptr<B> b;
};
闻呓 2024-10-24 23:18:47

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

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

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

One option would be to not explicitly store the A, but instead to use dynamic allocation to create a new A to store in the B:

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

Since this guarantees that the A is created before the B, this should prevent this problem from ever occurring.

彡翼 2024-10-24 23:18:47

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

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

class AB
{
public:
  AB():b_(&a_) {}

private:
  A a_;
  B b_;
};

现在类 C 可以通过使用 AB 代替 AB 来避免排序问题:

class C
{
public:
  ...
private:
  AB ab_;
};

如上所述,这当然假设 AB 之间存在 1:1 关系。如果一个 A 对象可以被许多 B 对象共享,事情就会变得更加复杂。

The problem is that you are shooting yourself in the foot with the third example. In C++ the order of member variables in a class/struct matters. No matter how you go about solving your particular problem, if you pass uninitialized data to a constructor due to poor class design / member layout, you will be working with unitialized data and possibly get undefined behavior, depending on the sort of code in place.

To address your particular example, if B really requires an A and the relationship is one to one, why not create a new class AB that has both an A object and a B object in the right order and pass the address of A to B. That is:

class AB
{
public:
  AB():b_(&a_) {}

private:
  A a_;
  B b_;
};

now class C can avoid the ordering problem by using AB instead of A and B:

class C
{
public:
  ...
private:
  AB ab_;
};

As forementioned, this of course assumes a 1:1 relationship between A and B. If an A object can be shared by many B objects, things get more complicated.

破晓 2024-10-24 23:18:47

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

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

   A* a;
   B* b;
};

这可以避免声明中的顺序问题,但会带来确保正确创建它们的新问题。另外,如果您经常创建大量 C 语言,则初始化列表会稍微快一些。

I'm not sure how much control you have over the implementation and structure of C but is it necessary to use the objects themselves in class C? Could you redefine the class to use pointers instead and then move them from the initialization list, e.g.

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

   A* a;
   B* b;
};

This avoids the issue of order in the declaration, but gives you the new issue of ensuring they're created correctly. Also, if you create A LOT of C's very often, an initialization list is slightly faster.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文