【问题标题】:C++ inheritance: child class instance uses both child and parent constructorsC++ 继承:子类实例同时使用子构造函数和父构造函数
【发布时间】: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,将你的答案发布为我的问题的答案,以便我选择它。

标签: c++ inheritance


【解决方案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 对象不同,那么您就不再需要继承了。 (虽然我认为这不是你想要的)

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

    【讨论】:

      猜你喜欢
      • 2020-12-21
      • 1970-01-01
      • 1970-01-01
      • 2018-06-06
      • 1970-01-01
      • 1970-01-01
      • 2012-11-14
      • 2012-09-03
      相关资源
      最近更新 更多