基类指针可以指向派生类对象。为什么反之亦然?

时间:2011-02-08 19:06:39

标签: c++

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

13 个答案:

答案 0 :(得分:128)

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

如果我告诉你我有一只宠物,你不知道这只动物是狗,它可能是一只猫,甚至可能是一只长颈鹿。在不知道一些额外信息的情况下,你无法安全地假设我有一只狗。

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

(你现在听到的吱吱声是类比拉伸)

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

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

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

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

ClassCastException Cat

答案 1 :(得分:11)

我们有两个对象。

class A {
   int a;
};

class B : A {
   int b;
};

分配B的实例。我们可以将其与A*B*进行对话。

分配A的实例。如果我们将其转换为B*,是否应为成员b分配空间?

答案 2 :(得分:9)

呃,因为基类不是派生类。

当你有一个指向某个类型的有效指针时,你会说指向的对象在某些位置会有某些数据,以便我们可以找到它。如果你有一个指向派生对象的指针,那么你可以保证指向对象包含所有Derived的数据成员 - 但是当你指向Base时,它实际上没有那个和Bad Things Happen™。 / p>

但是,Derived保证将所有Base数据成员放在相同的位置。这就是为什么指向Base的指针实际上可以指向Derived。

答案 3 :(得分:4)

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

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

答案 4 :(得分:3)

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

    Animal * pAnimal = new Tiger();

这是无效的,因为该物体不是毒镖蛙。

    PoisonDartFrog * pPoisonDartFrog = new GenericFrog();

答案 5 :(得分:1)

因为C ++是一种静态类型语言,并且允许隐式的Base-to-Derived转换会破坏类型系统。 Bjarne Stroustrup不希望任何“消息不被理解”的运行时错误。

答案 6 :(得分:1)

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

答案 7 :(得分:1)

简短答案

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;
}

答案 8 :(得分: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.

就原因而言:一般来说,基指针比派生指针更通用。因此,它对继承类型的了解较少。如果没有强制转换,则无法为派生指针指定基类型的指针,因为它无法判断基指针是派生类型还是其子类型。

答案 9 :(得分:0)

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

这是一个巨大的风险。

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

答案 10 :(得分:0)

通常,一种类型的指针不能指向另一种类型的对象。但是,此规则有一个重要例外,该规则仅与您衍生的类相关。 在这种情况下,BASE *类型的指针可能指向Derived类型的对象,即基类指针可以指向派生类对象,但反之亦然,因为基对象不是它的子类对象。

答案 11 :(得分:0)

这是因为“指针的类型是指针指向的对象的类型”。因此,

  1. 如果我们有基本类型的指针(* B):

然后,我们期望在B指向的地址处有一个基本类型的对象(并希望访问其功能),如果在该地址处获得了派生的类型对象,那么我们也可以访问所需的功能。这是因为派生类型是-基本类型。

  1. 如果我们派生了类型指针(* D):

然后,我们期望在D指向的地址处有一个派生类型对象,如果在那里获得基本类型对象,则由于基本类型不是-派生类型,我们将无法从该基本类型对象访问派生类信息

答案 12 :(得分:0)

行动胜于雄辩。 孩子也可以拥有父类对象。 如果您对指针的理解很好,那么限制就不对了 在下面的代码中,通过子类指针(具有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