首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对于指向同一基类的其他类的指针,C++11非静态数据成员统一初始化失败

对于指向同一基类的其他类的指针,C++11非静态数据成员统一初始化失败
EN

Stack Overflow用户
提问于 2012-05-21 05:10:53
回答 2查看 1.4K关注 0票数 5

我是一个老C-dude,试图通过将我的旧状态机框架从C移植到C++11来学习C++11,我的想法是为状态机本身创建一个类,然后为其中的状态创建嵌套类。状态可以是分层的,即超状态和子状态。框架需要知道状态的超状态,为此,我在嵌套的状态类中有一个指针(state *superstate)。

我的问题是,我打算通过在机器的类中直接使用构造函数来设置超级状态指针,这在使用非静态数据成员初始化的C++11中应该是可能的,通过使用统一初始化。但是由于某些原因,当它被设置为另一种类型的状态/类时,它无法编译(substateB3{superstateA})。但是,如果我稍后使用一个特定的函数(set_superstate)来设置它,它就可以很好地工作,该函数具有与构造函数相同的参数!有趣的是,如果我将superstate设置为相同类型的状态/类(substateB2{substateB1}),则构造函数会被接受。

我使用的是gcc 4.7.0 (为了获得对非静态数据成员初始值设定项的支持),下面是我的代码:

代码语言:javascript
复制
// My state-machine framework (simplified)
struct machine {
  struct state {
    state()                  : superstate(nullptr) { }     // No superstate => toplevel state!
    state(state &superstate) : superstate(&superstate) { }
    state *superstate;
    void set_superstate(state &superstate) { this->superstate = &superstate; } // Non-ctor way to set superstate
  };
};

// An example of a specific state-machine using my framework
struct Machine : machine {
  struct SuperstateA : state {
  } superstateA;

  struct SubstateB : state {
  } substateB1,              // Compiles OK; gets its superstate set in Machine's ctor below
    substateB2{substateB1},  // Compiles OK; but not correct superstate
    substateB3{superstateA}; // gcc 4.7.0 error: could not convert ‘{((Machine*)this)->Machine::superstateA}’ from ‘<brace-enclosed initializer list>’ to ‘Machine::SubstateB’

  Machine()  { substateB1.set_superstate(superstateA); } // Compiles OK;
} myMachine;

非常感谢您的任何建议或指导!:)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-05-21 07:04:45

剥离一层继承:

代码语言:javascript
复制
struct m {
    struct state { state *s;
        state() : s(0) {};
        state(state &s) : s(&s) {}
        set(state &s) { this->s = &s; }
    };

    struct s1 : state {} A;   // calls s1(), the default constructor
    struct s2 : state {}    B     // calls s2(), ditto
    ,                       C{B}  // calls s2(const s2&), the default copy constructor
    ,                       D{A}; // calls s2(const s1&)

    m() { B.set(A); } // The m() body runs after all the members are constructed.
} M;

你会得到构造错误,因为你的子状态没有声明构造函数,所以它们得到了编译器提供的默认值,并且没有来自兄弟类或基类的引用(编译器不提供s2(s1&)s2(state&))。

您得到了错误的C超级状态,因为C{B}调用了默认的复制构造函数s2(s2&),该函数在m()的正文之前运行。

下面是你想要的:

代码语言:javascript
复制
struct m {
    struct state { state *s; state() : s(0) {} state(state &s) : s(&s) {} };
    struct s1 : state {} A; // default-constructs, fine
    struct s2 : state {
        s2(state &s) : state(s) {}
        s2(s2&s)     : state(s) {}
    }            B     // default-constructs
    ,            C{B}  // calls s2(s2&), invokes state(state&)
    ,            D{A}; // calls s2(state&)
    ;
    m() : B(A) {};
} M;

当M的构造函数运行时,首先是它的基类(没有),然后是使用指定的初始化以声明顺序构造它的成员。只有一个:B(A),所以所有其他的都是默认的。在构造完所有的基础和成员之后,对象构造函数的主体就会运行。

票数 5
EN

Stack Overflow用户

发布于 2012-05-21 06:39:23

代码语言:javascript
复制
  struct SuperstateA : state {
  } superstateA;

  struct SubstateB : state {
  } substateB1, 
    substateB3{superstateA};

SuperstateASubstateB之间没有允许在它们之间进行转换或切片的关系。即使SuperstateA是一个基类(通常与“超级”相关联),SubstateB仍然会有更多的成员(作为子类),并且不可能从不同类型的对象全部初始化它们。

这不是编译器中的错误,也不是C++的任意限制。执行这种初始化是不可能的。需要有一种"is-a“的关系。

另一方面,superstateAsubstateB1都可以转换为state & (或者它们的指针可以转换为state *),因此提供SubstateB::SubstateB( state & )可以很好地修补所有漏洞。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10677237

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档