如何将基类对象分配给派生类对象?

时间:2011-01-01 18:55:55

标签: c++ inheritance

假设我有一个基类A和公开派生的B类,我应该如何将A对象分配给B的A基类子对象?

class A {...};
class B : public A {...};
A a(..);
B b(..);
static_cast<A&>(b) = a; ???

如果没有为B编写分配操作符,这是否可行?将铸件b投射到A&amp ;?是否存在任何潜在问题?符合标准吗?

6 个答案:

答案 0 :(得分:4)

这是一个非常糟糕的主意。 A是基础,B是派生类型。通过将B转换为A,您现在使用A的赋值运算符,它不会触及任何额外的派生数据。在该作业结束时,b仍被视为B类型,即使它现在包含A。这与继承的使用方式相反。

将行更改为b = reinterpret_cast<B&>(a);会更糟。然后你假装aB,当它不是,并且你正在阅读无效的记忆。

如果你真的想做这种作业,你想要:

class B : public A {
    B& operator= (const A& a) { ... }
};

然后你可以编写一个函数来复制A中的信息,并以某种方式处理派生类型B中的额外信息,再加上这将允许你简单地写:

b = a;

答案 1 :(得分:3)

编写另一个答案来演示为什么以及如何将基类对象分配给派生类对象。

struct TimeMachineThing_Data {
..
..
};

class TimeMachineThing : private TimeMachineThing_Data
{
    static std::stack<TimeMachineThing_Data> m_stateHistory;

    void SaveState() {
        m_stateHistory.push_back( static_cast<TimeMachineThing_Data&>(*this) );
    }

    void RestoreState() {
        static_cast<TimeMachineThing_Data&>(*this) = m_stateHistory.front();
        m_stateHistory.pop_front();
    }
};

这非常有用且完全合法。

(这里是私有继承,所以只有内部TimeMachineThing IS-A TimeMachinetime_Data)


另一个。

struct StructWithHundresField {
  string title;
  string author;
  ...

  StructWithHundresField() {
    ...
  }
};

class EasyResetClass : public StructWithHundresField {
  int not_reset_this_attriute;
public:
  void ResetToInitialStateAtAnyTime() {
    static_cast<StructWithHundresField&>(*this) = StructWithHundresField();
  }
}

答案 2 :(得分:2)

想一想这是否是个好主意。请记住,如果你有B亚类A,那么每个B都是A但不是每个A都是B.例如,每只狗都是哺乳动物,但不是每只哺乳动物都是狗。如果你有一个具体的B对象,在大多数情况下,尝试将它设置为A对象在数学上并不是很好定义的。而且,在C ++世界中,因为B对象被静态地键入为B,所以你永远不能为它指定一个类型为A的对象,这样它就会使它停止成为B.最好,你要覆盖它只是B对象的A部分而不改变任何B特定部分。

答案 3 :(得分:1)

在C ++中(与其他OOP语言一样)继承建立了Is-A关系。

即,如果B公开继承A,B = A.

您总是可以毫无顾虑地将B实例转换为A引用。

答案 4 :(得分:0)

我想说你需要一个专门将A对象复制到B对象的赋值运算符。

通常,在复制相同类型的对象时,任何方式都是一个好主意。但是不同类型的物体使它变得更加重要。

答案 5 :(得分:0)

每个人都应该知道赋值是一个协变二元运算符,因此无法正常使用虚函数。大多数二元运算符都是如此,但赋值是特殊的,因为它是C ++语言的一部分。

如果您正在使用OO,则您的对象应该是不可复制的并始终由指针表示。对象标识的唯一性是OO的核心:对象不是值,它们具有唯一值(它们的地址)。

如果您正在玩值,您应该使用适当的概念:函数式编程(FP)。这是闭包(应用对象),开关,模板,变体和其他东西。

在混合它们之前,尝试深入了解每个。一般而言FP包含OO,因此是一般方法:OO是在特殊情况下提供安全动态调度的特殊情况。 OO dispatch是线性的,这意味着它处理无限的子类型集,但它也只适用于属性(具有一个变量参数的函数,即对象),并且不能用于任何更高阶(具有多个变量参数的函数)。赋值只是另一个2-ary函数,因此无法使用虚函数进行调度。