C++中有两种类型的成员初始值设定项列表吗
Are there two types of member initializer lists in C++?
我看到了使用成员初始值设定项列表的两种不同方法。第一个是这样的:
class ClassName {
public:
arg_type_1 varName1;
arg_type_2 varName2;
// Constructor.
ClassName(arg_type_1 arg_name_1, arg_type_2 arg_name_2)
: varName1(arg_name_1), varName2(arg_name_2)
{
}
}
那里发生的事情很清楚。在构造函数中,我们有一个参数列表,并使用它们初始化类的成员。例如,arg_name_1
用于初始化类的varName1
变量的值。
另一种使用成员初始值设定项的方法出现在继承的情况下:
class ChildClass : public ParentClass
{
ChildClass(string name) : ParentClass( name )
{
// What can we put here and why we might need it.
}
};
这里发生的事情也很清楚。当我们用一个字符串参数调用ChildClass
的构造函数时,它用相同的字符串参数调用了ParentClass
的构造函数。
我不清楚的是编译器如何区分这两种情况(语法相同)。例如,在第二个例子中,编译器可能认为它需要取name
变量的值,并将其分配给ChildClass
的ParentClass
变量,然后它发现这样的变量没有在ChildClass
中声明。
我不清楚的第二点是,为什么我们可能想在第二个例子的构造函数的主体中放入一些内容。即使没有任何东西,它也已经创建并使用父类的构造函数返回对象。
我不清楚的是编译器如何区分这两种情况(语法相同)。
看到列表中的初始值设定项,编译器首先查找具有该名称的成员变量。如果它找到一个,它会尝试用给定的参数初始化该成员。如果没有,它将查找具有该名称的直接基类或虚拟基类,以使用给定的参数初始化基类子对象。当您在类的方法(包括构造函数)中命名某个对象时,通常会应用这些名称查找规则。
在极少数且设计糟糕的情况下,当成员变量和直接基类都具有相同名称时,必须限定基类类型,即添加名称空间:
struct B1 {
B1(char const*) {};
};
namespace Foo {
struct B2 {
B2(bool) {};
};
}
struct Weird : public B1, public Foo::B2 {
int B1;
double B2;
Weird()
: ::B1("meow")
, Foo::B2(false)
, B1(42)
, B2(3.14)
{}
};
我不清楚的第二点是,为什么我们可能想在第二个例子的构造函数的主体中放入一些内容。即使没有任何东西,它也已经创建并使用父类的构造函数返回对象。
它并没有真正返回任何对象,只是创建了那个对象。然而,有人可能想调用这样的附加函数:
class ParentClass {
public:
ParentClass(string name);
void registerSomething(ParentClass const&);
}
class ChildClass : public ParentClass {
public:
ChildClass(string name) : ParentClass( name ) {
registerSomething(*this);
}
};
可能有很多原因导致有人想要这样做。一般来说,由于子类比父类"更多",因此如果它想在构造函数中做更多的事情,而不仅仅是初始化基类子对象,这是很自然的。
关于对象生存期的一些词语:在进入构造函数主体之前,您只构造了新对象的子对象。当执行离开构造函数主体时,对象本身开始其生存期。一个类比可以是汽车及其零件:在进入汽车的构造车身之前,你已经给轮胎充气,组装好发动机,并冲压出车身的零件。但是,如果你的车还没有组装好,它就不是一辆车,这种情况发生在车身上。这在析构函数中是镜像的,尤其是在存在异常的情况下:如果在对象的构造函数中发生异常,则不会调用其析构函数。只有已经完全构造的子对象的析构函数才会被调用。这是因为,如果构造函数尚未完成执行,则对象永远不存在,也没有什么可调用的析构函数。
ParentClass
是一种类型,varName1
是一个变量。它们是两种不同类型的实体,每个编译器都应该加以区分。
当你想把一些代码放在子类ctor中时,有很多情况。例如,您希望根据基类对象的正确初始化来计算子类成员的初始值。
这些对编译器来说都是一样的:初始值设定项列表用于初始化子对象。如果子对象是基础类,它是根据其类型命名的;如果是成员,则命名为按成员名称;但这两种情况的原理是相同的。
通常的名称查找规则适用。如果您将与基类同名,它将隐藏基类,并且不能在初始值设定项列表中指定基类(意味着基类必须具有默认构造函数)。(不要这样做。建立一个命名约定,使类型名称和变量名称永远不会冲突。)
至于为什么您可能希望在构造函数,可能有很多原因。大多数情况下由于一些后期处理,您在初始化的成员。在其他情况下,可能是因为需要先进行一些预处理,然后才能初始化成员。或者您可能想要重构一些常见的处理输出到一个单独的函数中。
我不清楚的是编译器如何区分这两种情况(语法相同)。例如,在第二个例子中,编译器可能认为它需要获取name变量的值,并将其分配给ChildClass的ParentClass变量,然后它发现这样的变量没有在ChildClass中声明。
编译器知道ParentClass
是一个类型,而不是ChildClass
中的成员。您将无法声明名为ParentClass
的成员
我不清楚的第二点是,为什么我们可能想在第二个例子的构造函数的主体中放入一些内容。即使没有任何东西,它也已经创建并使用父类的构造函数返回对象。
这适用于想要在ParentClass
中使用某些特定的非默认构造函数的情况。
- 在C++中将函数压缩为两种方式
- 如何使映射键具有两种不同的数据类型?
- 两种访问I2C总线的方法有什么区别?
- 两种模板示例有什么区别?
- 如何构造可以调用和返回两种不同类型的模板
- 这两种C++语法之间有什么区别?
- 为什么两种不同的对象初始化方式给出不同的输出
- std::cin 从控制台获取两种不同的变量类型,'storing'以后使用第二种类型?
- 定义类模板构造函数的两种方法之间的区别
- 初始化类的两种方法?
- C++ 一个函数,可以根据接受的值返回两种类型之一
- 如何检查程序员在C++中提供的两种不同格式的输入
- C++指针中的这两种类型的值分配有什么区别?
- 如何在c ++中以一行(水平)打印两个文件的数据?如给定的.这两种形式来自两个不同的文本文件
- 有没有办法让C++函数采用具有相同成员的两种不同类型?
- C++两种类型相互依赖
- boostzip迭代器,用于两种不同的列表大小
- std::map 的这两种列表初始化形式有什么区别
- C++中有两种类型的成员初始值设定项列表吗
- 两种模板类型和两个模板参数列表有什么区别