C++ 基类指针可以指向派生类对象。为什么反之则不然?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4937180/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
A Base Class pointer can point to a derived class object. Why is the vice-versa not true?
提问by Zuzu
A Base Class pointer can point to a derived class object. Why is the vice-versa not true without casting? Logically a base class would not have enough information of the derived class but a derived class should have the information of the base class as well. I am missing some basics here.
基类指针可以指向派生类对象。为什么在没有铸造的情况下反之亦然?从逻辑上讲,基类不会有足够的派生类信息,但派生类也应该有基类的信息。我在这里缺少一些基础知识。
回答by jk.
If I tell you I have a dog, you can safely assume that I have a pet.
如果我告诉你我有一只狗,你可以放心地假设我有一只宠物。
If I tell you I have a pet, you don't know if that animal is a dog, it could be a cat or maybe even a giraffe. Without knowing some extra information you can't safely assume I have a dog.
如果我告诉你我有一只宠物,你不知道那只动物是狗,可能是猫,甚至是长颈鹿。在不知道一些额外信息的情况下,您不能安全地假设我有一只狗。
similarly a derived object is a base class object (as it's a sub class), so it can be pointed to by a base class pointer. However, a base class object is not a derived class object so it can't be assigned to a derived class pointer.
类似地,派生对象是基类对象(因为它是子类),因此它可以由基类指针指向。但是,基类对象不是派生类对象,因此不能将其分配给派生类指针。
(The creaking you will now hear is the analogy stretching)
(你现在听到的吱吱声是类比拉伸)
Suppose you now want to buy me a gift for my pet.
假设你现在想给我买一件礼物给我的宠物。
In the first scenario you know it is a dog, you can buy me a leash, everyone is happy.
在第一种情况下,你知道它是一只狗,你可以给我买一条皮带,每个人都很高兴。
In the second scenario I haven't told you what my pet is so if you are going to buy me a gift anyway you need to know information I haven't told you (or just guess), you buy me a leash, if it turns out I really did have a dog everyone is happy.
在第二种情况下,我没有告诉你我的宠物是什么,所以如果你打算给我买礼物,你需要知道我没有告诉你的信息(或者只是猜测),你给我买一条皮带,如果它原来我真的有一只狗,每个人都很高兴。
However if I actually had a cat then we now know you made a bad assumption (cast) and have an unhappy cat on a leash (runtime error).
然而,如果我真的有一只猫,那么我们现在知道你做了一个错误的假设(演员)并且有一只不快乐的猫被拴住(运行时错误)。
回答by Bill Lynch
We have two objects.
我们有两个对象。
class A {
int a;
};
class B : A {
int b;
};
Allocate an instance of B
. We can interface with that as either an A*
or a B*
.
分配一个实例B
。我们可以将其作为 anA*
或 a进行接口B*
。
Allocate an instance of A
. If we were to cast it to a B*
, should there be space allocated for the member b
?
分配一个实例A
。如果我们将其强制转换为 a B*
,是否应该为成员分配空间b
?
回答by Puppy
Uh, because the base class is not a derived class.
呃,因为基类不是派生类。
When you have a valid pointer to a type, then you are saying that the object pointed to will have certain data in certain locations so that we can find it. If you have a pointer to a derived object, then you are guaranteeing that the pointed-to object contains all of Derived's data members- but when you point to a Base, then it infact doesn't have that and Bad Things Happen?.
当您拥有指向类型的有效指针时,您就是说指向的对象将在某些位置具有某些数据,以便我们可以找到它。如果你有一个指向派生对象的指针,那么你就保证被指向的对象包含派生的所有数据成员——但是当你指向一个基类时,它实际上没有那个,坏事发生了吗?。
However, Derived is guaranteed to have all of the Base data members in the same locations. That's why a pointer to Base can actually point to Derived.
但是,Derived 保证所有 Base 数据成员都位于相同的位置。这就是为什么指向 Base 的指针实际上可以指向 Derived。
回答by Jonathan Wood
Because a derived class includes everything that is in the base class. But a base class does not include everything that is in the derived class.
因为派生类包括基类中的所有内容。但是基类不包括派生类中的所有内容。
Type casting a base class to a derived class is not recommended: What happens if you try to access members that are not part of the base class?
不建议将基类类型转换为派生类:如果您尝试访问不属于基类的成员会怎样?
回答by Andy Thomas
This is valid, because a tiger is an animal:
这是有效的,因为老虎是一种动物:
Animal * pAnimal = new Tiger();
This is not valid, because it is not true that the object is a poison dart frog.
这是无效的,因为该对象不是毒镖蛙。
PoisonDartFrog * pPoisonDartFrog = new GenericFrog();
回答by YoungJohn
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
回答by Peri Javia
The short answer
简短的回答
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;
}
回答by fredoverflow
Because C++ is a statically typed language, and allowing implicit Base-to-Derived conversions would break the type system. Bjarne Stroustrup did not want any "message not understood" runtime errors.
因为 C++ 是一种静态类型语言,并且允许隐式 Base-to-Derived 转换会破坏类型系统。Bjarne Stroustrup 不希望出现任何“无法理解消息”的运行时错误。
回答by Lee Louviere
If assign an address from a base class pointer into a derived class pointer, you can potentially assign a base class object to a derived class pointer. You run the risk of accessing derived class members when you don't have a derived class. Whereas derived class methods would work on a base class, they would only do so if the method didn't access derived class member data.
如果将基类指针的地址分配给派生类指针,则可以潜在地将基类对象分配给派生类指针。当您没有派生类时,您会冒着访问派生类成员的风险。虽然派生类方法可以在基类上工作,但只有在该方法不访问派生类成员数据时才会这样做。
That's a huge risk.
这是一个巨大的风险。
So we force you to cast so that you have to acknowledge the disclaimer that says (you may make a stupid mistake, please be careful).
因此,我们强制您强制转换,以便您必须承认声明中的免责声明(您可能犯了一个愚蠢的错误,请小心)。
回答by Washu
Because a base class pointer can point to an instance of the base class or any derived type. A derived pointer can only point to that derived type or any subclass of it.
因为基类指针可以指向基类或任何派生类型的实例。派生指针只能指向该派生类型或其任何子类。
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.
As far as the why goes: In general the base pointer is more general than the derived pointer. As such it knows less about the inherited type. A derived pointer cannot be assigned a pointer to a base type without casting simply because it cannot tell if the base pointer is of the Derived type or one of its children.
至于原因:一般来说,基指针比派生指针更通用。因此,它对继承的类型知之甚少。派生指针不能在不进行强制转换的情况下分配指向基类型的指针,因为它无法判断基指针是派生类型还是它的子代之一。