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

C++ 基类指针可以指向派生类对象。为什么反之亦然?,c++,C++,基类指针可以指向派生类对象。为什么没有铸造,反之亦然? 从逻辑上讲,基类没有足够的派生类信息,但派生类也应该有基类信息。 我这里缺少一些基础知识。嗯,因为基类不是派生类 当你有一个指向某个类型的有效指针时,你的意思是指向的对象将在某些位置有某些数据,这样我们就可以找到它。如果您有一个指向派生对象的指针,那么您可以保证指向的对象包含派生对象的所有数据成员——但是当您指向一个基时,它实际上没有这个指针,并且会发生不好的事情™. 但是,派生数据库保证所有基础数据成员位于相同的位置。这就是为什么指向Ba

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

嗯,因为基类不是派生类

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

但是,派生数据库保证所有基础数据成员位于相同的位置。这就是为什么指向Base的指针实际上可以指向派生对象。

我们有两个对象

class A {
   int a;
};

class B : A {
   int b;
};
分配
B
的实例。我们可以将其作为
A*
B*
接口


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

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

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.

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

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

    Animal * pAnimal = new Tiger();
这是无效的,因为该对象不是毒箭蛙

    PoisonDartFrog * pPoisonDartFrog = new GenericFrog();

如果我告诉你我有一只狗,你可以放心地认为我有一只宠物

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

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

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

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

在第一个场景中,你知道它是一只狗,你可以给我买条皮带,每个人都很高兴

在第二个场景中,我没有告诉你我的宠物是什么,所以如果你打算给我买礼物,你需要知道我没有告诉你的信息(或者只是猜测),你给我买一条皮带,如果我真的养了一条狗,每个人都会很高兴

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


< P>因为C++是静态类型的语言,允许隐式基类派生的转换会破坏类型系统。Bjarne Stroustrup不希望出现任何“消息未理解”运行时错误。

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


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

如果将地址从基类指针指定给派生类指针,则可以将基类对象指定给派生类指针。如果没有派生类,则可能会访问派生类成员。尽管派生类方法可以在基类上工作,但它们只有在方法不访问派生类成员数据的情况下才能这样做

这是一个巨大的风险

因此,我们强迫您投票,以便您必须承认免责声明(您可能会犯愚蠢的错误,请小心)。

简短答案

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

通常,一种类型的指针不能指向另一种类型的对象。然而,这个规则有一个重要的例外,它只与派生类相关

在这种情况下,类型为
BASE*
的指针可能指向类型为
Derived
的对象,即基类指针可以指向派生类对象,但反之亦然,因为基类对象不是它的子类对象。

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

  • 如果我们有基类型指针(*B):
  • 然后我们期望在B所指的地址处有一个基类型对象(并且希望访问它的功能),如果我们在该地址处得到一个派生类型对象,那么我们也能够访问所需的功能。这是因为派生类型是基类型

  • 如果我们有派生类型指针(*D):

  • 然后,我们期望在D所指的地址处有一个派生类型对象,如果我们在那里得到基类型对象,那么我们将无法从基类型对象访问派生类信息,因为基类型不是派生类型。

    操作所说的不仅仅是单词。 子类也可以有父类对象。 如果你能很好地理解指针,你就会受到限制 在下面的代码中,通过子类指针(具有父类对象)打印了这两个值。 通过打印他们的地址也证明了这一点。 欢迎提出任何建议

    #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 
    
    #包括
    使用名称空间std;
    类Baap{
    公众:
    INTA;
    
    void hoo(){cout@DeadMG:你在编辑过程中抓住了我。我认为一个例子有助于传达这一概念。三年后,今天的两位反对者是否愿意评论一下他们认为这个答案有缺陷的地方?…这个物体是毒箭蛙并不一定是真的…@Aryaman-这当然不是真的,有合理的理由
    #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