基类成员初始化
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 中,并在默认初始化后在构造函数的主体中分配。也就是说,在构造函数的主体中,对已创建的对象使用了赋值运算符。
【讨论】:
以上是关于基类成员初始化的主要内容,如果未能解决你的问题,请参考以下文章