为什么指向基类的指针可以指向子类的对象?

Why a pointer to the base class can point an object of the child class?

本文关键字:子类 对象 指针 基类 为什么      更新时间:2023-10-16

假设在C++中,如果我们有一个基类 Base 和一个派生的子类:

class Base{
protected:
int x_base;
};
class Derived : public Base {
public:
int x_prot;
};

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

Base *b;
b=new Derived;

但这是不允许的:

Derived *b;
b=new Base;

我会反其道而行之。

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

我的推理错误在哪里?

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

我们确实是这样说的。这是真的!每个Derived对象都以一个Base子对象开头。这就是继承的本质。Derived是一个Base加上最后的一些附加内容。

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

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

指针不分配东西。他们指向事物。

事实上,你的推理正是Derived* b=new Base;被破坏的原因——确实创造了一个对象的东西(即new(只是创建一个Base,而不是一个Derived。然后说b指向一个可以被视为完整Derived的东西,那简直是不真实的。你最后错过了所有其他的东西。

我的推理错误在哪里?

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

假设您邀请了一位水管工在下周二到您家。你只知道他是一个base plumber.您还知道有两种类型的水管工 - 基础和扩展。基地水管工可以修理管道。扩展的可以做基地做的事情,也可以安装热水器。你不知道哪个会来你的房子基地一个或扩展,所以可以安全地假设他是基地。所以当男人到达时,你可以要求他修理你的管道,你会没事的。但是,假设您还希望安装加热器。你不能要求这家伙安装它,因为他只是作为基地水管工来的。所以你有两个选择:

  1. 你告诉那个人 - 我不在乎你是谁,或者我看到你在其他地方做你的工作,或者我意识到的其他方式,所以我假设你是一个扩展的水管工。所以我现在打电话给你扩展,去安装我的加热器。因此,如果你的假设是正确的,你会没事的。如果你错了,那么这家伙可能会倒置安装热水器,可以完全制动它,甚至让你的整个房子爆炸。

  2. 问那个人:你是一个长期的水管工吗?如果他说是,那么你告诉他 - 安装加热器。所以你要么没事,要么不会完成工作。

所以回到你的案例 - 将扩展水管工视为基础是安全的,他们都可以修理管道。另一方面,假设水管工被延长是不安全的,所以你要么需要一种方法来知道这一点,要么问他。第一个由static_cast<>完成,第二个由dynamic_cast<>完成。但现在应该更清楚为什么将派生类指针(扩展管道工(转换为 base 是安全的,反之则不然。