【问题标题】:C++ prototype initialiser lists?C ++原型初始化程序列表?
【发布时间】:2011-09-18 14:36:25
【问题描述】:

如果我有以下代码(问题的简化版):

class TestA
{
    public:
    int A,B,C;

    TestA(){A = 1; B = 5; C = 10;}
};

//This is a referencing class to allow for universal and consistent operations
class TestB
{
   public:
   int &A, &B, &C; //Note references

   TestB(TestA &A) : A(A.A), B(A.B), C(A.C){}; //This is fine
   TestB(TestC &C) : A(C.A), B(C.B), C(C.C){}; //This needs to be prototyped
};

//Similar class to TestA but in the main program would have...
//...many different and conflicting variables and has to be treated as stand alone
class TestC
{
    public:
    int A, B, C;
    int Size;

    void Function()
    {
        TestB B(*this); //This uses TestB. TestB cannot be prototyped. 
        //etc etc
    }
};

我想知道,是否可以对基于初始化列表的构造函数进行原型化?

如果没有,有什么替代方案?请记住,引用必须立即初始化。

【问题讨论】:

  • “原型”的真正含义是什么?您是指需要单独的声明和定义,以便TestC 可用?
  • ctors 中的“原型”初始化列表是什么意思?
  • TestC 将自身的副本传递给 TestB,以便 TestB 可以引用回 TestC。然后将一个 TestA 复制到另一个 TestB,允许两个类(TestA 和 TestC)相互操作,并传递给 TestB 期望函数,而无需向下转换或向上转换(这可能涉及切片,因此会出现问题)。
  • @SSight,你能不能不只是做TestB(const TestC& t) 来互相传递你的课程?
  • TestB 预计会修改调用类。这只是问题的一个非常非常简单的版本。基本上原版都有模板类和子类,不想冒险切片,所以TestB基本上是通用的适配器类。

标签: c++ class reference


【解决方案1】:

如果“原型”是指函数声明和定义的分离,这应该可行:

class TestB {
   // ...
   TestB(TestC &C);
};

TestB::TestB(TestC &C) : A(C.A), B(C.B), C(C.C) {
};

【讨论】:

  • 优秀。谢谢你的回答。
  • @Branko:不过,你忘记了前向声明。
  • @Tomalak 没关系。我也是。但我知道它需要提前声明。我只是不知道(如何)制作初始化列表的原型。我意识到一旦构造函数开始访问它不可能知道的变量,就会发生冲突。
  • @SSight3:您的第一步是停止使用这种无意义的短语“原型化初始化列表”。它是一个“member 初始化器”,您不需要“原型化”它。
【解决方案2】:

如果要单独声明和定义带有成员初始化器列表的构造函数:

struct B;              // <-- (forward declaration of B)
struct A {
   A(B& b);            // <-- A ctor declaration
   B& b;
};

struct B {             // <-- (real definition of B)
   A a;
};

A::A(B& b) : b(b) {};  // <-- A ctor definition (with member-initialiser!)

成员初始化器列表与定义而不是声明一起使用。

【讨论】:

  • 我认为原型设计是指在初始化列表中声明使用的对象。
  • @pmr: 是的,他现在可以这样做,因为它的 use 已经在他的代码后面移到了其他地方。
  • 也感谢您的回答。
  • @SSight3:不客气。这些循环依赖可以与前向声明一起使用,但它们也有点设计味道,在大多数情况下应该避免。
【解决方案3】:

原来的问题已经回答了,但我忍不住对设计发表评论。

这 3 个类完全彼此相爱.. :).. 我的意思是不需要的循环依赖和紧密耦合等等..

为什么不让 TestC 和 TestA 扩展 TestB?

假设您有很好的理由不这样做,其他选择是:

在代码中读取 cmets

class TestX
{
public:
    int A,B,C;

    TestX()
    {
        A = 1;
        B = 5;
        C = 10;
    }
};

// "int A,B,C;" coming from baseclass now.
class TestA : public TestX {};

// fwd decl not needed anymore.
// class TestC;

class TestB
{
public:
    int &A, &B, &C; //Note references

    // dealing with TestX instead.
    TestB(TestX &X) : A(X.A), B(X.B), C(X.C) {};
};

class TestC : public TestX
{
public:
    // coming from baseclass now
    // int A,B,C;
    int Size;

    void Function()
    {
        // moved out to some other place.. main() in this case.
        // TestB B(*this);
    }
};

// not needed anymore..
// TestB::TestB(TestC &C): A(C.A), B(C.B), C(C.C) {}

int main ()
{
    TestC c;
    TestA a;

    TestB bc(c);
    TestB ba(a);

    // your primary usecase (referencing class to allow for universal and consistent operations)
    // is satisfied, without changing anything in the client code.
    // You can still use c as TestC where "int Size" or "Function" are needed.

    return 0;
}

现在的依赖是:

X <---- A
^   |__ C
|
B

【讨论】:

  • 这是一个聪明的主意,如果我重新设计,我可能会尝试合并它,但是我已经编写了很多头文件,并且原型/设计非常糟糕(我的自己的过错)。一旦我完成了基本的构建(工作班等),我希望将其提交给设计和改进批评。
  • 当然.. 请记住,您总会找到“很好的理由”来不立即做正确的事情。 :)
猜你喜欢
  • 2023-03-19
  • 2012-02-16
  • 1970-01-01
  • 2020-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-18
相关资源
最近更新 更多