基类指针可以指向派生类对象。如果不进行强制转换,为什么反之亦然?逻辑上,基类将没有足够的派生类信息,但是派生类也应具有基类信息。我在这里缺少一些基础知识。
Answers:
如果我告诉您我有一只狗,您可以放心地假设我有一只宠物。
如果我告诉您我有一只宠物,您不知道该动物是狗,可能是猫,甚至是长颈鹿。在不知道一些额外信息的情况下,您不能安全地假设我有一只狗。
类似地,派生对象是基类对象(因为它是子类),因此可以由基类指针指向。但是,基类对象不是派生类对象,因此无法将其分配给派生类指针。
(您现在听到的吱吱声是类比拉伸)
假设您现在想给我买宠物的礼物。
在第一种情况下,您知道它是狗,可以给我买皮带,每个人都很高兴。
在第二种情况下,我没有告诉您我的宠物是什么,因此,无论如何如果您要给我买礼物,您需要知道我没有告诉过您的信息(或只是猜测),如果您给我买了皮带,原来我真的有一只狗,每个人都很高兴。
但是,如果我实际上有一只猫,那么我们现在知道您做了一个错误的假设(投射),并且在皮带上有一只不快乐的猫(运行时错误)。
嗯,因为基类不是派生类。
当您拥有有效的指向类型的指针时,则表示所指向的对象将在某些位置具有某些数据,以便我们可以找到它。如果您有一个指向派生对象的指针,则可以保证所指向的对象包含派生对象的所有数据成员,但是当您指向Base时,它实际上并没有该对象和Bad Things Happen™。
但是,派生保证将所有基本数据成员都放在同一位置。这就是为什么指向Base的指针实际上可以指向Derived的原因。
这是有效的,因为老虎是动物:
Animal * pAnimal = new Tiger();
这是无效的,因为对象不是毒箭蛙是不正确的。
PoisonDartFrog * pPoisonDartFrog = new GenericFrog();
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
因为C ++是一种静态类型的语言,所以允许隐式的从基数到派生的转换将破坏类型系统。Bjarne Stroustrup不需要任何“无法理解的消息”运行时错误。
p->any_method_name(42, "hello", test);,如果存在接受三个参数的方法,则编译器将不会在编译时进行任何检查,因为他不知道p指向类的实例静态已知类型的。检查将推迟到运行时,这会花费更多,并且显然不可靠(但从正面看,更灵活-例如,您不需要子类型化或泛型)。
简短的答案
class A{
public:
method1();
};
class B: public A{
public:
method2();
};
int main(){
// Case 1
A* ptr_base = new B();
// Here I can call all the methods in A by ptr_base even though it is assigned B ...
// ... because B is derived from A and has all the information about methods of A
// Case 2
B* ptr_derived = new A(); // this will cause error
// Now here ptr_derived is assigned information of A ...
// ... So with this information can I call (*ptr_derived).method2(); ?...
// ... the answer is No because A does not have information of method2() ...;
// ... thus this declaration loses its meaning and hence error.
return 0;
}
因为基类指针可以指向基类的实例或任何派生类型。派生指针只能指向该派生类型或其任何子类。
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.
至于原因:一般而言,基本指针比派生指针更通用。因此,它对继承类型的了解较少。不能仅将派生指针分配给基本类型的指针,而不能进行强制转换,因为它无法判断基本指针是Derived类型还是其派生类型之一。
行动胜于语言。孩子也可以拥有父类对象。如果您对指针的理解很好,那么您就不受限制了。在下面的代码中,子类指针(具有Parent类对象)打印了两个值。还通过打印证明了自己的地址。欢迎任何建议!
#include<iostream>
using namespace std;
class Baap{
public:
int a;
void hoo(){ cout<<"hoo\n"; cout<<a;}
};
class Beta:public Baap{
public:
int a;
int b;
void hee(){ cout<<"hee\n"; }
};
int main(){
Baap baap;
baap.a=1;
Beta *beta=(Beta*)&baap;
baap.a=3;
beta->hee();
beta->hoo();
cout<<"\n beta = "<<beta<<"\n&baap = "<<&baap;
return 0;
}
//output
hee
hoo
3
beta = 0x7ffd11dd3834
&baap = 0x7ffd11dd3834
通常,一种类型的指针不能指向另一种类型的对象。但是,此规则有一个重要例外,该例外仅与派生类相关。
在这种情况下,类型的指针BASE*可能指向类型的对象Derived,即基类指针可以指向派生类对象,但反之亦然,因为基对象不是它的子类对象。