我将使用一个虚拟示例来描述我的问题。假设我们有一个这种架构的程序:
父类:四边形
子类:Rectangle,Rhombus,...
首先,生成vector<Rectangle>
和vector<Rhombus>
并使用其子类属性。稍后,我想组合所有四边形,即将两个向量组合成一个vector<quadrilateral>
,因为我不再需要子类属性。将两个向量组合成一个有一个优点,我可以将vector<quadrilateral>
的引用传递给我的程序的其他部分,在那里它与来自其他类的数据结合。
所以我的问题如下:是否可以通过仅保留Quadrilateral
中的父变量来从Rectangle
中生成Rectangle
?或者这是一个非常糟糕的主意,是否有更优雅的方式来实现这一点?
编辑:
在从这些被称为切片的答案中学习之后,我在What is object slicing?中了解了它。我决定采用Mohamad建议使用指针向量,因为我认为这是一个优雅的解决方案,可能会给我最好的表现。
答案 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*>;
这样就不会发生切片,如果这些类很大,你可能会从性能提升中获益,因为任何复制矢量都可能是指针而不是整个对象。