关于c ++:基类指针可以指向派生类对象。


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

基类指针可以指向派生类对象。为什么没有铸造,反之亦然?从逻辑上讲,基类将没有足够的派生类信息,但派生类也应该具有基类信息。我这里缺少一些基础知识。


如果我告诉你我有一只狗,你可以放心地假设我有一只宠物。

如果我告诉你我有宠物,你不知道那动物是狗,它可能是猫,甚至可能是长颈鹿。如果不知道一些额外的信息,你就不能安全地认为我养了一条狗。

类似地,派生对象是一个基类对象(因为它是一个子类),所以它可以由一个基类指针指向。但是,基类对象不是派生类对象,因此不能将其分配给派生类指针。

(你现在听到的吱吱声是比喻的延伸)

假设你现在想给我的宠物买件礼物。

在第一种情况下,你知道它是一只狗,你可以给我买一条皮带,每个人都很高兴。

在第二种情况下,我没有告诉你我的宠物是什么,所以如果你无论如何都要给我买礼物,你需要知道我没有告诉你的信息(或者只是猜测),你给我买了一条皮带,如果结果证明我真的养了一条狗,每个人都很高兴。

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

ClassCastException Cat


我们有两个物体。

1
2
3
4
5
6
7
class A {
   int a;
};

class B : A {
   int b;
};

分配B的一个实例。我们可以把它作为一个A*B*接口。

分配A的一个实例。如果我们把它投射到一个B*上,是否应该为成员B分配空间?


因为基类不是派生类。

当你有一个指向类型的有效指针时,你会说指向的对象在某些位置上会有一些数据,这样我们就能找到它。如果您有一个指向派生对象的指针,那么您保证指向的对象包含派生对象的所有数据成员——但是当您指向一个基,那么它就不会受到影响,并且会发生不好的事情?.

但是,派生的保证在同一位置上具有所有基本数据成员。这就是为什么指向基的指针实际上可以指向派生的。


因为派生类包含基类中的所有内容。但基类并不包括派生类中的所有内容。

不建议将基类强制转换为派生类:如果尝试访问不属于基类的成员,会发生什么情况?


这是有效的,因为老虎是动物:

1
    Animal * pAnimal = new Tiger();

这是无效的,因为这个物体不是真的是一只毒镖蛙。

1
    PoisonDartFrog * pPoisonDartFrog = new GenericFrog();


简短的回答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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不希望出现任何"消息无法理解"的运行时错误。


通常,一个类型的指针不能指向其他类型的对象。但是,这个规则有一个重要的例外,它只涉及YO派生类。在这种情况下,类型base*的指针可以指向派生类型的对象,即基类指针可以指向派生类对象,反之亦然,因为基对象不是它的子类对象。


如果将一个地址从一个基类指针分配到一个派生类指针中,则可以潜在地将一个基类对象分配给一个派生类指针。如果没有派生类,则有访问派生类成员的风险。虽然派生类方法可以在基类上工作,但是只有当方法不访问派生类成员数据时,它们才会这样做。

这是一个巨大的风险。

所以我们强迫你投,所以你必须承认免责声明说(你可能犯了一个愚蠢的错误,请小心)。


因为基类指针可以指向基类或任何派生类型的实例。派生指针只能指向该派生类型或其任何子类。

1
2
3
4
5
6
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.

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