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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:57:17  来源:igfitidea点击:

A Base Class pointer can point to a derived class object. Why is the vice-versa not true?

c++

提问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).

然而,如果我真的有一只猫,那么我们现在知道你做了一个错误的假设(演员)并且有一只不快乐的猫被拴住(运行时错误)。

ClassCastException Cat

ClassCastException 猫

回答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.

至于原因:一般来说,基指针比派生指针更通用。因此,它对继承的类型知之甚少。派生指针不能在不进行强制转换的情况下分配指向基类型的指针,因为它无法判断基指针是派生类型还是它的子代之一。