C++ 继承:子类实例同时使用子构造函数和父构造函数

Posted

技术标签:

【中文标题】C++ 继承:子类实例同时使用子构造函数和父构造函数【英文标题】:C++ inheritance: child class instance uses both child and parent constructors 【发布时间】:2015-08-14 21:03:03 【问题描述】:

我正在练习 C++ 中的继承,但遇到了一些构造函数问题。

当我创建子类 (Circle) 的实例时,它会同时创建子类和父类的实例。还是这样?

我只想创建一个 Circle 的实例,而不是 shape 和 circle。

如果我从 Circle 的构造函数中删除 : Shape(0,0),则会收到错误消息:“Shape 类不存在默认构造函数”

你总是要引用父类的构造函数吗?这意味着总是调用父级的构造函数?这是否意味着同时存在子实例和父实例?

儿童班:

#include "Circle.h"
#include <iostream>

using namespace std;

Circle::Circle(float radius) : Shape(0.0, 0.0) 
   this->radius = radius;


float Circle::computeArea() 

    cout << "Circle area is " << (3.14 * radius * radius) << "\n";
    return float(3.14 * radius * radius);

父包:

#include "Shape.h"
#include <iostream>

using namespace std;

Shape::Shape(float base, float height) 
   this->base = base;
   this->height = height;

   cout << "Shape: base - " << base << " height - " << height << "\n";



float Shape::computeArea() 

   cout << "Area is " << base*height << "\n";
   return base * height;

主包:

#include "Circle.h"
#include "Square.h"
#include <iostream>

using namespace std;


int main() 

    Square mySquare(10.0, 10.0);
    Circle myCircle(5.0);

    float squareArea = mySquare.computeArea();
    float circleArea = myCircle.computeArea();

    cout << "done";


    return 0;

输出:

形状:底 - 10 高度 - 10 形状:底 - 0 高度 - 0 面积为 100 圆形面积为 78.5 完成了

【问题讨论】:

那么问题是什么? 如果您对Shape 的构造函数被调用感到惊讶,那么您认为您在这里做什么:Circle::Circle(float radius) : Shape(0.0, 0.0)? (派生类是(也是)一个父类,并且必须构建自身的“父”部分,因此在其构造函数中调用其构造函数) 那么当从父级继承时,你总是和子级一起创建父级的实例? @Spectrem 不,有一个实例,但它既是形状又是圆形,因为圆形是形状。所以这个单一实例也将运行 Shape 和 Circle 构造函数。但是,您可以在 Shape 中定义多个构造函数,并从 Circle 构造函数中选择要运行的构造函数。但是,这可能会让阅读您的代码的其他人更难理解。 Wimmel,将你的答案发布为我的问题的答案,以便我选择它。 【参考方案1】:

我认为您混淆了术语。也就是说,您将作为角色的父级与基类混淆了。

如果一个圆是一个形状,那么当然通过创建一个圆你也将创建一个形状,因为圆是一个形状。这是不可避免的,也是完全正确的。但形状不会是一个额外的对象,它会被包含在圆内,是它不可分割的一部分。

你总是要引用父类的构造函数吗?

并非总是如此,如果您有一个默认构造函数,无论是没有参数的还是带有默认参数的,您都可以省略它并隐式获取默认构造函数。但是由于Shape 只有一个带参数的构造函数,所以你必须指定它。圆是一种形状,所以在你有圆之前,你必须有一个形状。

如果将构造函数更改为Shape::Shape(float base = 0.0, float height = 0.0),则可以将其从派生类的初始化列表中省略。

父类与基类完全不同,父子关系是关于所有权的,例如在确定性垃圾收集的情况下,子类的生命周期与父类的生命周期相关联。

【讨论】:

【参考方案2】:

在我看来,您的代码没有问题,您只是对继承在 C++ 中的工作方式感到困惑。

每次你从基类派生一个类时,在进入子类构造函数之前,如果基类构造函数没有参数,编译器会自动为你调用它。例如,如果你的 Shape 类有这样的构造函数

Shape::Shape() 

那么子类就不必在初始化列表中调用基类构造函数(编译器会为你做这件事)。现在你的构造函数看起来像这样:

Circle::Circle(float radius) 
   this->radius = radius;

如果您没有没有参数的构造函数,则必须在初始化列表中显式调用它。

Circle 类型的每个对象都是一种形状,里面包含更多信息。这并不意味着编译器创建两个对象只是因为它也初始化了父组件,你仍然有一个对象。

现在,如果您希望您的 Circle 与您的 Shape 对象不同,那么您就不再需要继承了。 (虽然我认为这不是你想要的)

你不能/不想避免调用基类构造函数,这就是继承的全部意义:它允许你扩展一个对象的特性,它基于另一个对象的实现。

【讨论】:

以上是关于C++ 继承:子类实例同时使用子构造函数和父构造函数的主要内容,如果未能解决你的问题,请参考以下文章

关于C++子类构造函数的重载问题

继承中子类构造函数相关问题

Python 3:当子构造函数的参数多于父构造函数时,从继承的方法返回新的子类实例

C++中如何在子类的构造函数中调用基类的构造函数来初始化基类成员变量

C++中子类从基类都继承啥?

C++中,继承时,创建子类对象,能否在子类构造函数初始化列表里调用基类构造函数?