基类成员初始化

Posted

技术标签:

【中文标题】基类成员初始化【英文标题】:Base class members initalization 【发布时间】:2020-03-28 12:17:31 【问题描述】:

为什么下面的代码不允许我初始化基类成员:

class A  
public:
   int x;
;

class B : public A 
public:
    B() : x(0)  // error
;

虽然以下是:

class A  
public:
   int x;
;

class B : public A 
public:
    B()  x = 0;  // ok
;

【问题讨论】:

“为什么”很难明确回答。但是现代 C++ 问题的解决方案是在 A 类定义中写 public: int x = 0; 成员初始值设定项列表仅适用于类的直接成员,而不适用于继承的成员。您应该考虑创建A 的默认构造函数,在其中初始化A 的成员,或者如@hyde 所述,对变量进行内联初始化。 【参考方案1】:

因为基类被视为初始化列表中的成员。

您可以像这样描绘B 类型的对象:

class C 
public:
    A parent;
;

在此示例中,您将无法初始化 parent.x,而只能初始化 parent。 即使您可以访问和修改正文中的parent.x,就像您所做的那样,您也无法访问其在初始化列表中的成员:

C::C() 
    parent.x = 5; // Works


C::C() : parent.x(5)  // Won't work

另一方面,如果你有 A 的构造函数,就像

A::A(int i): x(i) 

,您可以在 C 的初始化列表中使用此构造函数:

C::C(): parent(5)  // Works and does what you want

如果你有 A 的构造函数,你对 B 有同样的选择:

B::B(): A(5) 

【讨论】:

【参考方案2】:

这段代码sn-p

class A  
public:
   int x;
;

class B : public A 
public:
    B() : x(0)  // error
;

不正确,因为根据 C++ 标准(12.6.2 初始化基和成员)

2 在 mem-initializer-id 中,在构造函数类的范围内查找初始的非限定标识符,如果在该范围内找不到,则在包含构造函数定义的范围内查找。 [注:如果构造函数的类包含与该类的直接或虚拟基类同名的成员,则命名该成员或基类并由单个标识符组成的mem-initializer-id指的是类成员。可以使用限定名称指定隐藏基类的 mem-initializer-id。 — end note ] 除非 mem-initializer-id 命名构造函数的类,构造函数类的非静态数据成员,或该类的直接或虚拟基类,否则 mem-initializer 是非良构的。

你可以写

class A  
public:
   int x;
;

class B : public A 
public:
    B() : A 0  
;

在 mem-initializer-list 中使用直接基类标识符的位置。

注意这里使用了大括号A 0 而不是括号,因为class A 是一个聚合。

在这段代码中sn-p

class A  
public:
   int x;
;

class B : public A 
public:
    B()  x = 0;  // ok
;

数据成员x 不存在于mem-initializer-list 中,并在默认初始化后在构造函数的主体中分配。也就是说,在构造函数的主体中,对已创建的对象使用了赋值运算符。

【讨论】:

以上是关于基类成员初始化的主要内容,如果未能解决你的问题,请参考以下文章

初始化基类成员的首选方法 (c++)

可以通过[重复]在派生类中初始化受保护的基类成员

C ++为所有派生类初始化抽象基类受保护成员

派生类:在初始化列表中使用基类成员

为啥不能在派生类的构造函数初始化列表中初始化基类的数据成员?

C++中的派生类,可以不定义对象直接调用基类的成员和调用自己的成员函数嘛???