为什么指向基类的指针可以指向子类的对象? 在C++中,如果我们有基类基类和派生类子类: class Base{ protected: int x_base; }; class Derived : public Base { public: int x_prot; };

为什么指向基类的指针可以指向子类的对象? 在C++中,如果我们有基类基类和派生类子类: class Base{ protected: int x_base; }; class Derived : public Base { public: int x_prot; };,c++,pointers,C++,Pointers,我们可以创建一个指向基类的指针,并让它指向派生类对象: Base *b; b=new Derived; 但这是不允许的: Derived *b; b=new Base; 我的想法正好相反 当我们调用Base*b时,我们对代码说b将是指向类Base的对象的指针。在本例中,他将准备为x_base(但不为x_prot)分配空间。因此,我们不能使用基类的指针指向子类的对象 我的推理错误在哪里 当我们调用Base*b时,我们对代码说b将是指向类Base的对象的指针 我们确实是这样说的。这是真的!每个派

我们可以创建一个指向基类的指针,并让它指向派生类对象:

Base *b;
b=new Derived;
但这是不允许的:

Derived *b;
b=new Base;
我的想法正好相反

当我们调用
Base*b
时,我们对代码说
b
将是指向类
Base
的对象的指针。在本例中,他将准备为
x_base
(但不为
x_prot
)分配空间。因此,我们不能使用基类的指针指向子类的对象

我的推理错误在哪里

当我们调用
Base*b
时,我们对代码说
b
将是指向类
Base
的对象的指针

我们确实是这样说的。这是真的!每个
派生的
对象都以一个子对象开始。这就是继承的本质。一个
派生的
是一个
基础
加上一些附加的东西

制作一个完全忽略末尾附加内容的指针是非常好的:这就是向上投射所做的

在本例中,他将准备为
x_base
分配空间(但不为
x_prot

指针不分配东西。它们指向一些东西

事实上,你的推理正是为什么
Derived*b=newbase被破坏-创建对象(即
新建
)的东西只是创建一个
基础
,而不是
派生的
。然后说
b
指向一个可以被视为完整
派生
的东西是不真实的。你错过了结尾的所有附加内容

我的推理错误在哪里


我认为你认为指针是创建对象的东西,但事实并非如此。它们是指由其他东西(例如,
new
)创建的对象。

假设你邀请了一位水管工在下周二到你家来。你知道的唯一一件事就是他是一个卑鄙的管道工。你也知道有两种类型的管道工-基础管道工和延伸管道工。水管工人可以修理管子。扩展型用户可以做基础用户所做的事情,也可以安装热水器。你不知道哪一个会来你家基地一个或扩展,所以可以安全地假设他是基地。所以当那个人来的时候,你们可以请他修理你们的管道,你们会没事的。但假设您也希望安装加热器。你不能要求这个家伙安装它,因为他是作为一名基础管道工来的。因此,您有两种选择:

  • 你告诉那个家伙——我不在乎你是谁,或者我见过你在其他地方做你的工作,或者我意识到的其他方式,所以我假设你是一个长期的水管工。所以我现在打电话给你,去安装我的加热器。因此,如果你的假设是正确的,你会没事的。若你们错了,那个么这个家伙可能会把热水器倒过来安装,可能会把它完全刹住,甚至会让你们整个房子爆炸

  • 你问那个家伙:你是一个延长水管工吗?如果他说是,你就告诉他——安装加热器。所以你要么没事,要么就不干了


  • 所以回到你们的情况——把延长水管工当作基础水管工是安全的,他们都可以修理管子。从另一方面来说,假设一个水管工被延长了时间是不安全的,所以你要么需要一个知道的方法,要么问问他。第一个是通过
    静态_cast
    完成的,第二个是通过
    动态_cast
    完成的。但是现在应该更清楚了,为什么将派生类指针(扩展管道工)转换为base是安全的,而不是相反。

    每个
    派生的
    都是
    base
    ,但反之则不正确。在第二个示例中,似乎可以使用a如果执行了
    b->x_prot
    <代码>基本
    没有
    x\u保护
    。将
    分配给
    派生*
    没有意义。类对象所需的指针和空间是两个完全无关的主题。请注意,应该避免裸
    ,多态性需要指针(或引用),但这与是否动态分配是正交的。使用
    Base b;基准*p=&b
    如果您想要一个指向
    基本对象的原始指针(除非您确实需要动态分配的对象),这几乎肯定是一个重复,但它不是“太宽”。非常感谢您的解释。因此,如果这种推理方式是正确的,当我执行“Base*b=new-Derived”时,我将在堆上为派生对象(使用new)分配内存,然后我将只能访问类“b”继承的成员,因为指针只有这些属性。这是正确的推理吗?其他成员“迷路了”?[PS:在堆栈上进行分配时,根据对注释的观察,使用“派生c;Base*b;b=&c”进行类似的原因]@Thomas:是的,这是正确的。但是,请注意,您仍然可以执行
    static\u cast(b)
    来“将它们取回”,因为仍然存在一个完全有效的
    派生的
    对象供您使用(或者
    dynamic\u cast
    ,但如果没有
    virtual
    之类的东西,这就没什么用处了,这就是我们通常通过对基类成员使用虚拟分派来解决这个“问题”的方法)。是的,如何分配并不重要。这只是指针如何工作。谢谢!我知道这有点离题了,但做“Base*b=new-Derived”而不是简单的“Base*b=new-Base”有什么好处呢,因为我在任何情况下都只能访问基属性?我知道如果我有一个虚拟函数作为基的成员和派生的相应成员,我将覆盖基的虚拟函数。但这是唯一的优势吗(