从子类的构造函数主体调用基类的构造函数
Calling a constructor of the base class from a subclass' constructor body
我的印象是不可能,例如:在C 中的其他一些说明之后,调用基类的构造函数
但是以下程序运行并产生了两行"构造者":
#include <iostream>
class Person
{
public:
Person()
{
std::cout << "Constructor Person" << std::endl; }
};
class Child : public Person
{
public:
Child()
{
c = 1;
Person();
}
int c;
};
int main()
{
Child child;
return 0;
}
第一个是默认构造函数的隐式调用,这很明显。第二个 - 这意味着标题中描述的动作是合法的吗?我使用Visual C 2010。
儿童类构造函数中的调用不是调用基类构造函数,它正在创建一个临时,未命名和新对象类型的人。当构造函数退出时,它将被破坏。要澄清,您的示例与这样做是相同的:
Child() { c = 1; Person tempPerson; }
除非在这种情况下,临时对象具有名称。
,如果您对示例进行一些修改,您可以看到我的意思:
class Person
{
public:
Person(int id):id(id) { std::cout << "Constructor Person " << id << std::endl; }
~Person(){ std::cout << "Destroying Person " << id << std::endl; }
int id;
};
class Child : public Person
{
public:
Child():Person(1) { c = 1; Person(2); }
int c;
};
int main() {
Child child;
Person(3);
return 0;
}
这会产生输出:
Constructor Person 1
Constructor Person 2
Destroying Person 2
Constructor Person 3
Destroying Person 3
Destroying Person 1
以下是"加速C "的摘录:"派生的对象是由:
构造的1.为整个对象分配空间(基类成员以及派生的类成员);
2.调用基础级构造函数以初始化对象的基类部分;
3.根据构造函数初始化器指示的派生类成员的初始化;
4.执行派生级构造函数(如果有)。"
总结答案和评论:从子类的构造体主体中呼叫基类的构造函数是不可能的,因为上面的#2必须先于#4。但是我们仍然可以在派生的构造体主体中创建一个基本对象,从而调用基本构造函数。它将是一个与当前执行的派生构造函数构建的对象不同的对象。
您无法从子构建器的正文中调用它,但是您可以将其放入初始化列表中:
public:
Child() : Person() { c = 1; }
当然,请致电父级的默认构造函数,因为这将自动发生。如果您需要将参数传递给构造函数,则更有用。
您无法从身体调用构造函数的原因是,C 保证父母将在子构建器启动之前完成构造。
这个问题的答案通常在技术上是真实且有用的,但不要给出大图。大局与看起来有些不同:)
-
基类的构造函数是始终调用的,否则在派生类的构造函数的主体中,您将拥有部分构造的,因此可以使用不可用的对象。您有向基类构造函数提供参数的选项。这不是"调用"它:无论如何它都会被调用,您只需向其传达一些额外的论点:
// Correct but useless the BaseClass constructor is invoked anyway DerivedClass::DerivedClass() : BaseClass() { ... } // A way of giving arguments to the BaseClass constructor DerivedClass::DerivedClass() : BaseClass(42) { ... }
-
c 语法对明确调用构造函数具有怪异的名称,并且要符合此名称,因为这很少做 - 通常仅在库/基础代码中。它称为放置新,不,它与内存分配无关 - 这是在C 中明确调用构造函数的怪异语法:
// This code will compile but has undefined behavior // Do NOT do this // This is not a valid C++ program even though the compiler accepts it! DerivedClass::DerivedClass() { new (this) BaseClass(); /* WRONG */ } DerivedClass::DerivedClass() { new (this) BaseClass(42); /* WRONG */ } // The above is how constructor calls are actually written in C++.
因此,在您的问题中,这是您的意思,但不知道:)我想象这种怪异的语法是有帮助的(例如,Pascal/delphi)可以编写许多看似有效的代码,这些代码将以各种方式完全破坏。未定义的行为不是崩溃的保证,这就是问题所在。肤浅/明显的UB通常会导致崩溃(例如NULL指针访问),但是很多UB都是沉默的杀手。因此
-
"第二选项"在问题中,与构造函数无关。创建
BaseClass
对象值的默认构造实例的C 语法是:// Constructs a temporary instance of the object, and promptly // destructs it. It's useless. BaseClass(); // Here's how the compiler can interpret the above code. You can write either // one and it has identical effects. Notice how the scope of the value ends // and you have no access to it. { BaseClass __temporary{}; }
在c 中,对象实例的构造概念是无所不在的:您一直都在做,因为语言语义将对象的存在等同于已构造的对象。因此您也可以写:
// Constructs a temporary integer, and promptly destructs it. int();
整数类型的对象也是构造和破坏的 - 但是构造函数和破坏者很微不足道,因此没有开销。
请注意,这种方式的构建和破坏并不意味着任何堆的库。如果编译器确定必须实际实现一个实例(例如,由于构造或破坏的可观察副作用),则实例是一个临时对象,就像在表达式评估中创建的临时性一样 - A -HA,我们注意到
type()
是表达!因此,在您的情况下,
Person();
语句是一个否。在发行模式中编译的代码中,没有生成机器说明,因为没有办法观察此语句的效果(对于特定Person
类的情况),因此,如果没有人可以听到树的掉落,然后,这棵树不需要首先存在。这就是C 编译器优化内容的方式:他们做很多工作以证明(从数学意义上是形式上的)是否可能无法观察到任何代码的效果,如果这样,该代码被视为死亡代码并删除。
是的,我知道这已经一岁了,但我找到了一种方法。这可能不是最好的做法。例如,从派生的类构造函数中销毁基类实例听起来像是灾难的食谱。您可以跳过destructor步骤,但是如果基类构造函数进行任何分配,这可能会导致内存泄漏。
class Derived : public Base
{
public:
Derived()
{
// By the time we arrive here, the base class is instantiated plus
// enough memory has been allocated for the additional derived class stuff.
// You can initialize derived class stuff here
this->Base::~Base(); // destroy the base class
new (this) Base(); // overwrites the base class storage with a new instance
}
};
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 参数包构造函数在类模板中隐藏用户定义的转换
- 具有已删除移动和复制构造函数的类的就地构造
- 创建一个没有复制构造函数的类的 std::vector 的 std::vector
- C++构造函数和类?
- 在 C++ 中,默认情况下构造函数为类的数据成员提供的值是多少?
- 如何在其他类中使用参数化构造函数制作类的对象?
- 具有值包装器的可变参数模板构造函数的类构造函数优先级
- 如何使用私有构造函数对类进行单元测试?
- C++虚拟函数:基类函数是调用的,而不是派生的
- c++17在编译时将带有已删除复制构造函数的类添加到std::vector
- 从作为模板参数传递给构造函数的类继承,或者从它们继承
- 继承的构造函数忽略类内初始化
- 模板和隐式构造函数的类定义之外的友元声明
- 具有字符串文本构造函数的类不适用于 const 引用初始化
- 为什么具有私有构造函数的类不阻止从此类继承?如何控制哪些类可以从某个基继承?
- 具有多个非默认构造函数基的Singleton派生类
- 调用基默认构造函数模板类
- 当基类未指定构造函数时,如何使用仅具有带参数的构造函数的类派生基类?
- 构造所有基类不需要默认生成的构造函数