将子转换为父对象

时间:2015-10-01 16:23:24

标签: c++ inheritance

我将使用一个虚拟示例来描述我的问题。假设我们有一个这种架构的程序:

父类:四边形

子类:Rectangle,Rhombus,...

首先,生成vector<Rectangle>vector<Rhombus>并使用其子类属性。稍后,我想组合所有四边形,即将两个向量组合成一个vector<quadrilateral>,因为我不再需要子类属性。将两个向量组合成一个有一个优点,我可以将vector<quadrilateral>的引用传递给我的程序的其他部分,在那里它与来自其他类的数据结合。

所以我的问题如下:是否可以通过仅保留Quadrilateral中的父变量来从Rectangle中生成Rectangle?或者这是一个非常糟糕的主意,是否有更优雅的方式来实现这一点?

编辑:

在从这些被称为切片的答案中学习之后,我在What is object slicing?中了解了它。我决定采用Mohamad建议使用指针向量,因为我认为这是一个优雅的解决方案,可能会给我最好的表现。

2 个答案:

答案 0 :(得分:1)

是的,你可以这样做。您可以从子对象创建父对象,如下例所示:

struct Base { int base; };

struct Derived : Base { int derived; };

Derived der;
Base base = der;

该进程被称为slicing,它在这里工作,因为Base类将具有默认的复制构造函数,将const引用带到Base。由于派生可以自动转换为const引用它的基础,所以一切都像魅力一样。不过,我不确定整体设计。通常要避免切片。

在评论中提出一些问题后,我相信,有些澄清是有道理的。

与外观相反,Base base = der;不会调用赋值运算符。相反,它调用复制构造函数 - 这是变量声明的语义。它相当于Base base(der)。这是一个更具侵略性的例子:

struct A {
   A(int ) { };
   A() = default;
   // A(const A& ) = delete;
};

A a = 5; // Are your eyes fooling you?

不要相信你的眼睛!从来没有一个operator =被调用 - 在A中没有even运算符=。相反,在语义上调用A(int)构造函数来创建临时A,然后使用复制构造函数来创建一个对象。但是,编译器通常会优化对copy-constructor的调用,并且不会创建冗余的临时副本。为了确保这种情况,取消注释标记为delete的复制构造函数,程序将拒绝编译。

答案 1 :(得分:0)

是的,你可以通过'切片'对象的派生部分来做到这一点。

class Base {};
class Derived : public Base {};

Derived d;
Base b = d; // derived portion is sliced here

然而在实践中,我从未见过任何故意选择切割物体的人。我们通常会被警告为C ++的“gotacha”。

为什么不使用指针向量:

vector<Rectangle*>;
vector<Rhombus*>;
vector<quadrilateral*>;

这样就不会发生切片,如果这些类很大,你可能会从性能提升中获益,因为任何复制矢量都可能是指针而不是整个对象。