从成员初始化器列表中调用基方法

Calling base methods from member initializer list

从成员初始化列表中调用非虚基方法安全吗?和虚拟?

在所有基类初始化之前调用任何成员函数(虚拟或非虚拟)是不安全。下面是标准 ([class.base.init]§16) 中给出的示例:

class A {
public:
  A(int);
};

class B : public A {
  int j;
public:
  int f();
  B() : A(f()),     // undefined behavior: calls member function but base A not yet initialized
  j(f()) { }        // well-defined: bases are all initialized
};

class C {
public:
  C(int);
};

class D : public B, C {
  int i;
public:
  D() : C(f()),     // undefined behavior: calls member function but base C not yet initialized
  i(f()) { }        // well-defined: bases are all initialized
};

还有subtle cases.

正如我在评论中所说:

派生 class 的初始化列表中首先初始化的是基 class。明确地看起来像这样:

class A{ ... };

class B : public A {
    int x, y;
    B() : A{}, x{...}, y{...} {
        ...
    }
};

因此,在初始化 xy 时,您可以调用 A 的任何 非虚拟 方法,因为它已经被构建。

问题的第二部分与virtualness没有太大关系-它只是一个问题,您是否可以在构造函数中调用成员函数。答案是 是的,但是 - 你需要确保你没有使用对象的任何未初始化部分。

例如

struct Base {
    virtual int f(int i) = 0;
};

struct Derived : public Base {
    int x;
    int y;

    virtual int f(int i) override { return i; }

    Derived(int i) : Base{}, x{f(i)}, y{f(x)} {}
};

可以,但是写... Derived(int i) : Base{}, x{f(y)}, y{f(i)} ...就不行了。