【问题标题】:Why can't a Base class object be assigned to a Derived class object?为什么不能将基类对象分配给派生类对象?
【发布时间】:2018-02-02 02:46:51
【问题描述】:

派生类对象可以分配给 C++ 中的基类对象

Derived d;
Base b = d; // It's Ok

但是为什么不能将基类对象分配给派生类对象

Base b;
Derived d = b; //Not Ok. Compiler give an error

编辑:

抱歉,这个问题其实是在面试的时候问的。

【问题讨论】:

  • 因为这完全没有意义。或者,也许您可​​以解释一下为什么您认为它应该是可能的,以及这种行动的结果应该是什么。
  • @juanchopanza 其实这个问题是在采访中问的。
  • 用“OOP 导论”的话来说:每个苹果都是水果,但不是每个水果都是苹果。
  • @rsp 想一想结果会是什么,是得出没有意义的结论的好方法 :-) 我想这就是面试官想要触发的。 (不是我的反对票。)
  • 一个明显的问题不一定是一个糟糕的问题。请不要以明显的主观理由投反对票。这个问题很明确。

标签: c++ c++11 object inheritance derived-class


【解决方案1】:

如果存在公共继承 b/w Base 和 Derived 类,那么这就是“是”关系。

而在“是”关系中,Derived 是一个基础。

这里最重要的一点是“is a Relation”不是双向的。

即Derived 是 Base 但 Base 不是 Derived。

假设我们有两个类 Shape 和 Circle。

Shape 是一个基础,而 Circle 公开地继承自 Shape。

所以,圆是一个形状,但形状不是圆

//main.cpp
#include <iostream>
#include <string>

using namespace std;

class Shape
{
private:
    int x;
public:
    Shape(int i):x{i}
    {
        cout << "Base constructor called " << endl; 
    }
};

class Circle : public Shape
{
private :
    string color;  
public : 
    Circle(int radius) : Shape{ radius } 
    {
        cout << "Derived constructor called " << endl;
    }
    Circle(int radius, string color) : Shape{ radius }, color{ color }  
    {
        cout << "Derived constructor called " << endl;
    }
};


int main()
{
    //This is valid .  since a circle is a shape 
    Circle s(1);
    Shape a = s;

    return 0; 
} 

但你不能这样做,因为 Shape 不是圆形 而且这里的继承不是双向的

 Shape s(1);
 Circle a = s;

如果你这样做,你会得到一个编译器错误

  no suitable user-defined conversion
        from "Shape" to "Circle" exists

【讨论】:

    【解决方案2】:

    派生对象是基础对象,带有附加信息。

    你可以从派生对象的基础部分初始化一个完整的基础对象,没问题。

    但是如果你想从一个基础对象构造一个派生对象,应该用什么来初始化额外的信息呢?

    如果您想为该附加信息提供默认值,您可以通过声明Derived(Base const &amp;) 构造函数来实现。但由于它在一般情况下不起作用,因此不适合您。

    【讨论】:

    • 这应该是被接受的答案。所有那些“因为 a 是 b b 不是 a”并不能真正解释什么。
    【解决方案3】:

    使用临时引用怎么样?

    Base b;
    Derived d;
    Base & d_ref = d;
    d_ref = b;
    

    【讨论】:

    • 这没有回答问题。
    • 从技术上讲,它不能回答原始问题。我认为这是对一个类似且非常实用的问题的回答,“如何将基类对象分配给派生类对象?”这就是我找到这个帖子的方式,我在其他地方找不到答案。
    【解决方案4】:

    通常,C++ 编译器不允许将基类的对象分配给派生对象,因为从某种意义上说,派生类是基类的超集:即它不知道如何处理具有特定于派生类的任何成员。

    也就是说,您可以通过适当的赋值运算符重载和派生类中的适当构造函数来手动编码这种可能性。

    除了可能使语言过于复杂之外,我不明白为什么不能将可简单复制的基类实例分配给不包含其他成员的派生类。但在我撰写本文时,任何 C++ 标准都没有实现这一点。此外,至少在我看来,拥有任何未初始化的派生类成员和绕过派生类构造函数的后果并不需要程序员更多地考虑对象切片的危险,如果一个派生类实例被分配给基类!换句话说,我认为陈腐的反驳“因为它没有意义”本身并没有多大意义。

    参考:http://en.cppreference.com/w/cpp/types/is_trivially_copyable

    【讨论】:

      【解决方案5】:

      继承是一种“is-a”关系,但它是单向的

      如果你有例如

      struct Base { /* ... */ };
      struct Derived : Base { /* ... */ };
      

      那么DerivedBase,但Base 不是 Derived

      这就是为什么您可以使用派生对象分配或初始化基类实例(但要注意object slicing),但不能反过来。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-13
        • 2015-11-07
        • 2016-08-20
        • 2012-01-13
        • 2018-04-29
        • 1970-01-01
        • 2014-09-19
        • 1970-01-01
        相关资源
        最近更新 更多