精华内容
下载资源
问答
  • 如何用指针指向类对象
    万次阅读 多人点赞
    更多相关内容
  • 基类指针指向派生类对象、派生类指针指向基类对象 以下代码运行后的输出结果是() #include using namespace std; class A { public: void virtual print() { cout << "A" << endl; } }; class ...

    基类指针指向派生类对象、派生类指针指向基类对象

    以下代码运行后的输出结果是()

    #include using namespace std;
    class A
      {
    public:
      void virtual print()
        {
          cout << "A" << endl;
        }
    };
     
    class B : public A
    {
    public:
        void virtual print()
        {
            cout << "B" << endl;
        }
    };
    int main()
    {
        A* pA = new A();
        pA->print();
        B* pB = (B*)pA;
        pB->print();
        delete pA, pB;
        pA = new B();
        pA->print();
        pB = (B*)pA;
        pB->print();
    }
    using namespace std;
    class A{
        public:void virtual print(){
            cout << "A" << endl;}
        };
    class B : public A{
        public:void virtual print(){
            cout << "B" << endl;}
        };
        int main(){
            A* pA = new A();//基类指针指向基类对象
            pA->print();
            B* pB = (B*)pA;//派生类指针指向基类对象
            pB->print();
            delete pA, pB;
            pA = new B();//基类指针指向派生类对象
            pA->print();
            pB = (B*)pA;//派生类指针指向派生类对象
            pB->print();
    }
    

    在这里插入图片描述

    解答:

    1. A* pA = new A()//基类指针指向基类对象,毫无疑问调用的是A类的print
      输出A

    2. B* pB = (B*)pA;//派生类指针指向基类对象,这里疑问会比较大。首先是为什么这里不会报错,为什么派生类指针指向基类对象可以成立?理论上指针的可访问范围一定大于对象的大小,会指向一些未知区域导致运行出错,但是要注意的是,这个题目里面B类不存在新增数据成员,所以不会出错。还有就是由于是基类对象,还没有发生虚函数掩盖
      输出A

    3. pA = new B();//基类指针指向派生类对象。基类指针之所以可以访问派生类对象是因为指针的可访问范围一定小于对象的大小,所以做完切割即可,即切割一些派生类中存在而基类中不存在的成员即可。此时派生类对象的vptr指向的虚函数表中,派生类虚函数已经把基类同名虚函数掩盖掉了,所以指向的肯定是派生类虚函数
      输出B

    4. pB = (B*)pA;//派生类指针指向派生类对象。注意此时pA指向的是派生类对象
      输出B

    总结:(在分析完运行不出错的前提下)看指向的对象是啥类型,而不是看指针的类型

    这题涉及到的知识点

    虚函数预备常识

    需要知道一些常识,一个类所有的函数都是再code代码区中唯一的存放一份。而数据成员则是每个对象存储一份,并按照声明顺序依次存放。
    类A中有了虚函数就会再类的数据成员的最前面添加一个vfptr指针(void** vfptr),这个指针用来指向一个vtable表(一个函数指针数组)(一个类只有一个该表),该表存储着当前类的所有 虚函数 的地址。这样vfptr就成为了一个类似成员变量的存在。访问虚函数的时候通过vfptr间址找到vtable表,再间址进而找到要调用的函数。这样就在一定程度上摆脱了类型制约。

    示例:

    (People类是基类,student类是People类的派生类, Senior类是Student派生类)
    在这里插入图片描述
    (在虚函数表中,基类的虚函数在 vtable 中的索引(下标)是固定的,不会随着继承层次的增加而改变,派生类新增的虚函数放在 vtable 的最后。如果派生类有同名的虚函数遮蔽(覆盖)了基类的虚函数,那么将使用派生类的虚函数替换基类的虚函数,这样具有遮蔽关系的虚函数在 vtable 中只会出现一次。)

    只要vptr的值不同,那么访问函数成员的时候使用的vtable表就不同,就可能访问到不同类的函数成员。B类对象中的vptr指向B类自己的vtable。
    当B类继承A类的时候,因为A中有虚函数,编译器就自动的给B类添加vfprt指针和vtable表。也可以理解为B类继承来了A类中的那个vptr指针成员
    当A类指针指向B类对象时,发生假切割。要知道这个过程只是切掉A类中没有的那些成员。(即当People类指针指向Student类对象时,切割掉m_score这个People类中没有的成员)
    由于vptr是从A类中继承来的,所以这个量仍将保留。而对于vptr的值则不会改变,仍然指向B类的vtable表。所以访问F1函数的时候是通过B类的vtable表去寻址的,自然就是使用子类的函数(拿图中的情况举例,子类的Student::display()函数已经覆盖了People::display()函数,此时A类指针访问虚函数display()时也是访问到子类的Student::display()函数)。

    当B类的指针指向A类的对象时(当B类存在新增数据成员时可能出错),同理。

    而对于普通函数则受类型的制约,(因为没有vptr指针)使用哪个类的指针调用函数,那么所调用的就是那个累的函数。
    总而言之,普通函数通过对象或指针的类型来找所调用的函数,而虚函数是通过一个指针来找到所要调用的函数的。

    示例

    #include <iostream.h>
    
    class A
    {
    public:
    virtual void F1()
    {
    cout<<"A1"<<endl;
    }
    void F2()
    {
    cout<<"A2"<<endl;
    }
    
    };
    class B :public A
    {
    public:
    void F1()
    {
    cout<<"B1"<<endl;
    }
    void F2()
    {
    cout<<"B2"<<endl;
    }
    
    };
    void main(){
    
    A *pa;
    B *pb;
    B TB;
    A TA;
    
    pa = &TB;//基类指针指向派生类对象
    pa->F1();
    pa->F2();
    
    pb =(B *) &TA;//派生类指针指向基类对象
    
    pb->F1();
    pb->F2();
    
    }
    输出:
    B1
    A2
    A1
    B2
    

    基类指针指向派生类对象:如果基类声明的不是虚函数就调用基类的,如果是虚函数并在派生类中实现,就调用派生类的函数;
    派生类指针指向基类对象:如果基类声明的是虚函数就调用基类的,如果不是虚函数并在派生类中实现,就调用派生类的函数.

    理由见上

    参考

    【1】C++ 派生类指针指向基类对象

    展开全文
  • 当B指针指向A对象时(当B存在新增数据成员时可能出错),同理。 而对于普通函数则受类型的制约,(因为没有vptr指针)使用哪个的指针调用函数,那么所调用的就是那个累的函数。 总而言之,普通函数...
    源程序:#include <iostream.h>
    
    class A
    {
    public:
       virtual void F1()
     {
      cout<<"A1"<<endl;
     }
     void F2()
     {
      cout<<"A2"<<endl;
     }
    
    };
    class B :public A
    {
    public:
     void F1()
     {
      cout<<"B1"<<endl;
     }
     void F2()
     {
      cout<<"B2"<<endl;
     }
    
    };
    void main(){
    
     A *pa;
     B *pb;
     B TB;
     A TA;
    
     pa = &TB;//基类指针指向派生类对象
     pa->F1();
     pa->F2();
    
     pb =(B *) &TA;//派生类指针指向基类对象
    
     pb->F1();
     pb->F2();
    
    }
    
      
    以上程序输出结果:
    B1
    A2
    A1
    B2
    解释一下: 一个类所有的函数都是再code代码区中唯一的存放一份。而数据成员则是每个对象存储一份,并按照声明顺序依次存放。 类A中有了虚函数就会在类的数据成员的最前面添加一个vfptr指针(void** vfptr),这个指针用来指向一个vtable表(一个函数指针数组)(一个类只有一个该表),该表存储着当前类的所有虚函数的地址。这样vfptr就成为了一个类似成员变量的存在。访问虚函数的时候通过vfptr间址找到vtable表,再间址进而找到要调用的函数。这样就在一定程度上摆脱了类型制约。 基类在定义并实现了自己的虚函数后,在全局内存区域中(可以这么理解),会有一个虚函数表,里面都是已实现的函数的指针。程序运行过程中实例化的所有基类对象,都有一个指向虚函数表的指针,而且这个指针的值是一样的,都指向那个全局内存。因为对于基类的每个实例他们使用的函数代码都是一样的嘛。当你定义了一个派生类,并重新实现了部分虚函数后,由于你实现的虚函数和基类不同,所以必须有另一块全局内存保存派生类的虚函数指针列表。最简单的派生情况下,你的派生类就是在基类的内存块之后又加了些派生类使用的内存,此种最简单的情况下,你的派生类其实可以直接使用基类的那个指向虚函数列表的指针,只是指针的值是不同的而已。它指向不是基类的虚函数列表,而是派生类的虚函数列表。如果你没有定义新的虚函数,那么派生类的虚函数列表和基类布局一样,只是函数地址值不同,否则会在后面增加你新定义的函数的地址。 通过以上分析,我感觉如果你的派生类不对基类的虚函数做任何重新实现或补充,理论上可以使用同一个虚函数表,否则不行。 只要vptr的值不同,那么访问函数成员的时候使用的vtable表就不同,就可能访问到不同类的函数成员。B类对象中的vptr指向B类自己的vtable。当B类继承A类的时候,因为A中有虚函数,编译器就自动的给B类添加vfprt指针和vtable表。也可以理解为B类继承来了A类中的那个vptr指针成员。 当A类指针指向B类对象时,发生假切割。要知道这个过程只是切掉A类中没有的那些成员,由于vptr是从A类中继承来的,所以这个量仍将保留。而对于vptr的值则不会改变,仍然指向B类的vtable表。所以访问F1函数的时候是通过B类的vtable表去寻址的,自然就是使用子类的函数。 当B类的指针指向A类的对象时(当B类存在新增数据成员时可能出错),同理。 而对于普通函数则受类型的制约,(因为没有vptr指针)使用哪个类的指针调用函数,那么所调用的就是那个累的函数。 总而言之,普通函数通过对象或指针的类型来找所调用的函数,而虚函数是通过一个指针来找到所要调用的函数的。

    转自https://blog.csdn.net/hehe6378/article/details/40267603

    展开全文
  • 基类指针指向派生类对象

    千次阅读 2021-06-20 15:06:25
    基类指针指向派生类对象,只能调用基类原有的,而不能调用派生中的 从pa=&b,这里可看出,解释一下:这里取得是b的首地址,而pa的长度是由数据类型的内存所占大小决定的 pb=&a 的话是会报错的,因为pb的...

    在这里插入图片描述
    A作为基类,B作为派生类
    基类指针指向派生类对象,只能调用基类原有的,而不能调用派生类中的
    从pa=&b,这里可看出,解释一下:这里取得是b的首地址,而pa的长度是由数据类型的内存所占大小决定的
    pb=&a 的话是会报错的,因为pb的长度已经超出了A的内存范围,多出的那一部分可能会乱指,导致安全性缺失
    当然pb->showA()也是会报错的,同样的道理。
    所以,派生类指针不能指向基类对象

    构造函数能定义为虚函数?
    不能,虚函数是需要通过对应的vtable虚指针来调用,而虚指针是在对象创建完毕才有的,但是构造函数是要在对象创建时调用,这之间无法同时达到要求,所以构造函数不能定义为虚函数。

    用基类的指针去指向对象,在析构时就会出现问题,因为派生类对象在析构时是先释放派生类,再释放基类(正确的做法),而用基类指针指向派生类对象,析构时是只析构基类(错误的做法),从而导致派生类的那一部分没有被释放掉,成为僵尸内存或称内存泄漏
    所以用基类指针指向派生类对象,要用virtual析构函数,使基类指针可以指向派生类中(virtual的作用:根据对象的实际类型,调用相应的类型函数。),使得再手动释放内存delete 时,可以调用派生类的析构函数,从而自动调用基类的析构函数。

    展开全文
  • 指向对象的常指针指向对象指针变量声明为const型,并使之初始化,这样指针值始终保持为其初始值,不能改变。 代码如下:Time t1(10,12,15),t2;Time * const ptr1=&t1;ptr1=&t2;定义指向对象的常指针的一般形式为...
  • C++的基类指针指向派生类对象

    千次阅读 2022-03-09 09:21:34
    1、基类指针指向派生类对象 同名同参函数,基类虚函数、派生实函数 只要调用该名字的函数,都是调用派生函数 同名同参函数,基类实函数,派生虚函数 只要调用该名字的函数,都是调用基类函数 同名同参...
  • 假设基类(父类)是Base,派生(子类)是...但实际上这是错误的,这样得到的派生类指针是不能指向派生的成员函数或者数据成员。 而应该使用reinterpret_cast强制类型转换进行转换。 Derived d; Base *bp =...
  • C++对象指针-指向对象指针

    千次阅读 2021-06-10 20:26:59
    1 对象指针 学习C语言的时候,我们已经学习了指针的相关知识。例如: int a; int* pa = &a;... 此时,我们定义一个int类型的变量a,同时...所以,可以定义C++类对象指针变量,与C语言中定义int, float, stru...
  • 一、父类指针指向子类对象 先上代码: class Base { public: void base_fun1() {} virtual void base_fun2() { cout << "this is Base fun2()" << endl; } public: int a_a; protected: int a...
  • C++父类指针指向子类对象的实现原理

    千次阅读 多人点赞 2021-01-02 22:11:34
    1 前言 记得当初阿里面试的时候被问道这个问题,平时自己面对这个方法都习以为常的使用,C++多态和动态绑定不就是这么实现的嘛,但是还真没有刻意... 如果以一个派生类类指针指向一个基础类对象,必须先做强制转型动作
  • 为什么需要基类指针指向派生类对象? 我们知道虚函数可以让我们的具备多态的功能,你肯定在此会有所疑惑,为什么需要基类指针指向派生类对象?派生指针自己就能实现的功能,何必基类指针来多此一举呢?其实这...
  • 基类指针指向子类对象

    万次阅读 多人点赞 2018-07-03 10:10:44
    没有指定虚函数, 那么它就只能访问到类型对应的函数基类指针...正常情况,子类祖先的析构函数都是虚拟的,这样删除祖先类指针、子类对象的时候,可正确同时调用子类和祖先的析构函数):#include &lt;iost...
  • 父类指针指向子类实例对象,对于普通重写函数时,会调用父类中的函数。而调用被子重写虚函数时,会调用子类中的函数。 这是因为子类中被重写的虚函数的运行方式是动态绑定的,与当前指向实例的父类指针类型无关...
  • c++之:基类的指针指向派生类对象

    千次阅读 2019-11-06 16:56:41
    基类的指针指向派生对象,调用函数时: ①成员函数为虚函数,则调用派生中的成员函数,找真正实现的函数 ②成员函数不是虚函数,则调用基类中的成员函数 #include "iostream" using namespace std; class A { ...
  • 在基类与派生之间,有一个规定:派生类对象的地址可以赋给指向基类对象指针变量(简称基类指针),即基类指针也可以指向派生类对象。为什么有这一规定呢?因为它可以实现多态性【1】,即向不同的对象发送同一个...
  • class Base { public: int a }; class Child :public Base { public: ...Base占内存大小范围:int a;...Child占内存大小范围:int a;...基类指针(Base)指向派生(Child): Base *p = new Child(); ...
  • 数组指针——指向数组对象指针

    千次阅读 2020-04-20 22:52:49
    数组指针——指向数组对象指针 数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element)。数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存。以int arr[] = { 99,...
  • c++父类指针指向子类对象

    千次阅读 2018-11-08 15:50:04
    1,如果以一个基础类指针指向一个衍生类对象(派生类对象),那么经由该指针只能访问基础定义的函数(静态联翩) 2,如果以一个衍生类指针指向一个基础类对象,必须先做强制转型动作(explicit cast),这种做法很...
  • 父类指针可以指向子类对象

    千次阅读 2021-03-24 13:47:01
    结论:父类指针可以指向子类对象,但是只能访问父类成员,不能访问子类成员 结论:子类指针不可以指向父类对象,需要类型转换才可以 ...所以父类指针指向子类时,没有问题 ,因为父类有的...
  • 1、B指针指向A对象 首先看这么一个例子: #include &amp;amp;amp;amp;amp;amp;lt;iostream&amp;amp;amp;amp;amp;amp;gt; using namespace std; class A{ public: A(){ a = 1; b = 2; } ...
  • 指向对象指针 在建立对象时,编译系统会为每一个对象分配一定的存储空间,以存放其成员。对象空间的起始地址就是对象的指针。可以定义一个指针变量,用来存放对象的指针。 如果有一个: class Time { public ...
  • 父类指针指向子类对象

    千次阅读 2019-09-26 17:03:52
    缺点:父类指针,只能使用父类的成员 优点:提高复用性 要解决这个缺点, 多态 。 #include using namespace std; class CPerson { public: int a; public: void AA() { cout ()" ; } }; class ...
  • 基类的指针指向派生对象

    千次阅读 2018-05-24 20:46:09
    说明:只要基类的成员函数是虚函数,派生的同名函数(参数相同,返回值类型相同),函数体不同,不管有没有显式声明virtual都是虚函数。派生中virtual关键字可有可无,但是也是虚函数。#include "stdafx.h&...
  • 基类指针pBase指向派生类对象basePlus,基类与派生含有同名同参的函数,pBase调用函数应该调用哪个,当函数有虚函数时又该调用哪个? 先上结论: 基类指针pBase指向派生类对象basePlus时,基类与派生都含有...
  • 1,如果以一个基础类指针指向一个衍生类对象(派生类对象),那么经由该指针只能访问基础定义的函数(静态联翩) 2,如果以一个衍生类指针指向一个基础类对象,必须先做强制转型动作(explicit cast),这种做法...
  • 简而言之就是父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。但仅仅可调用父类含有的函数,非父类函数不能调用。 普通虚函数调用 假设我们有下面的层次: #include &lt;...
  • 即:没有虚函数的继承:如果一个基础(父类)指针指向派生(子类),那么该指针只能调用基础(父类)定义的函数(如果子类重写了函数,那么因为定义的是父类指针掉的将会是父类的函数,即根据指针的原型来确定...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 632,070
精华内容 252,828
热门标签
关键字:

如何用指针指向类对象