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++ 继承:子类实例同时使用子构造函数和父构造函数的主要内容,如果未能解决你的问题,请参考以下文章
Python 3:当子构造函数的参数多于父构造函数时,从继承的方法返回新的子类实例