基类指针可以指向派生类对象。 为什么反之亦然?
基类指针可以指向派生类对象。 反之亦然,为什么不铸就不成? 从逻辑上来说,基类没有足够的派生类的信息,但派生类也应该具有基类的信息。 我在这里错过了一些基础知识。
如果我告诉你我有一只狗,你可以放心地假设我有一只宠物。
如果我告诉你我有一只宠物,你不知道那只动物是一只狗,它可能是一只猫,甚至可能是一只长颈鹿。 不知道一些额外的信息,你不能安全地认为我有一只狗。
类似的派生对象是一个基类对象(因为它是一个子类),所以它可以通过基类指针指向。 但是,基类对象不是派生类对象,因此无法将其分配给派生类指针。
(你现在将听到的吱吱声是类比拉伸)
假设你现在想为我的宠物买一件礼物。
在第一种情况下,你知道这是一条狗,你可以给我买一条皮带,每个人都很高兴。
在第二种情况下,我没有告诉你我的宠物是什么,所以如果你要给我买一件礼物,你需要知道我还没有告诉你的信息(或者只是猜测),如果你给我买皮带事实上,我真的有一只狗,每个人都很高兴。
但是,如果我真的有一只猫,那么我们现在知道你做了一个错误的假设(铸造),并有一个不幸的猫(运行时错误)。
我们有两个对象。
class A { int a; }; class B : A { int b; };
分配一个B
的实例。 我们可以将它作为A*
或B*
进行交互。
分配A
一个实例。 如果我们把它投给B*
,是否应该为会员b
分配空间?
呃,因为基类不是派生类。
当你有一个有效的指针指向一个types,那么你就是说,指向的对象将在某些位置有一定的数据,以便我们可以find它。 如果你有一个指向派生对象的指针,那么你要保证指向的对象包含Derived的所有数据成员,但是当你指向一个Base时,它实际上并没有那个和Bad Things Happen™。
但是,派生保证所有的基础数据成员在相同的位置。 这就是为什么一个指向Base的指针实际上可以指向Derived。
这是有效的,因为老虎是一种动物:
Animal * pAnimal = new Tiger();
这是无效的,因为这个物体不是真正的毒镖蛙。
PoisonDartFrog * pPoisonDartFrog = new GenericFrog();
因为派生类包含基类中的所有内容。 但是基类不包含派生类中的所有内容。
不build议将基类转换为派生类:如果尝试访问不属于基类的成员,会发生什么情况?
因为C ++是一种静态types的语言,并且允许隐式的基于派生的转换会破坏types系统。 Bjarne Stroustrup不希望有任何“消息未理解”运行时错误。
class Base { public: int a; } class Derived : public Base { public: float b; } Base * pBase = new Base(); pBase->a = 7; // setting the value of a in the base // make a pDerived that points to the SAME DATA as pBase Derived * pDerived = pBase; pDerived->a = 5; // this would be okay, base has a public member 'a' pDerived->b = 0.2f; // error pBase has no data member b and pDerived // points to the SAME DATA as pBase
因为基类指针可以指向基类的实例或任何派生types。 派生指针只能指向派生types或其任何子类。
struct Base {}; struct Derived : Base {}; struct Derived2 : Base {}; Base* p = new Derived(); //Fine, Derived inherits from Base Derived* d = new Base(); //Not fine, Base is not an instance of nor derived from Derived. Derived* d2 = new Derived2(); // Also not fine, Derived2 derives from Base, but is not related to Derived.
至于为什么会这样:通常基指针比派生指针更一般。 因此,它对inheritancetypes知之甚less。 一个派生指针不能被分配一个指向基types的指针而不需要转换,因为它不能告诉基指针是派生types还是它的一个子types。
如果将基类指针的地址分配给派生类指针,则可以将基类对象分配给派生类指针。 如果没有派生类,则存在访问派生类成员的风险。 虽然派生类方法可以在基类上工作,但只有在方法不能访问派生类成员数据时才会这样做。
这是一个巨大的风险。
所以我们强迫你施放,这样你必须承认这个声明(你可能犯了一个愚蠢的错误,请小心)。