精华内容
下载资源
问答
  • 我们知道要实现运行时的多态, 必须在基类中声明和定义相关的虛函数, 并在派生类中重新实现基类中的虛函数. 当编译器见到这种继承层次结构的时候, 编译器将为定义了虛函数的基类和覆盖了基类虛函数派生类分别创建...

    我们知道要实现运行时的多态, 必须在基类中声明和定义相关的虛函数, 并在派生类中重新实现基类中的虛函数.
    当编译器见到这种继承层次结构的时候, 编译器将为定义了虛函数的基类和覆盖了基类虛函数的派生类分别创建一张虛函数表(Virtual Function Table, VFT), 也就是说通过编译器的编译, 基类和派生类的代码中都将有自己的虛函数表.
    为这些类创建实例化对象时, 会在实例化的对象中插入一个指向对应的虛函数表的指针 (VFT*), 该指针通常在存放在对象的开头区域.
    而虛函数表(VFT)可以看做就是一个其数据类型为函数指针的静态数组, 每一个函数指针指向对应类中的一个虛函数.

    例如:
    基类:

    class Base
    {
    public:
        virtual void Func1()
        {
        // Func1 implementation
        }
        virtual void Func2()
        {
        // Func2 implementation
        }// .. so on and so forth
        virtual void FuncN()
        {
        // FuncN implementation
        }
    };

    派生类:

    class Derived: public Base
    {
    public:
        virtual void Func1()
        {
        // Func2 overrides Base::Func2()
        }
        // no implementation for Func2()
        virtual void FuncN()
        {
        // FuncN implementation
        }
    };

    类Base和Derived的虛函数表

    Derived objDerived;
    objDerived.Func2();

    上述代码中编译器将查找objDerived对象所属的Derived类的VFT, 确保能够调用Base::Func2()函数.

    void DoSomething(Base& objBase)
    {
        objBase.Func1();
        // invoke Derived::Func1
        }
        int main()
        {
        Derived objDerived;
        DoSomething(objDerived);
    };

    在上述代码中, 虽然将派生类的对象objDerived通过引用传递给了objBase, 进而被解读为一个Base类的实例, 但是该实例的VFT*依然指向Derived类的虛函数表, 因此通过基类引用调用Func1()函数时, 实际上被调用的是派生类的虛函数Derived::Func1(). 注意必须是基类的指针或引用来调用基类虛函数, 而不能是直接传值, 因为传值会造成对象的切除, 切除派生类对象相对于基类对象多出来的部分, 造成最终调用的函数是基类的函数, 而不是我们想要的派生类中的覆盖版本.

    参考文献: Sams.Teach.Yourself.Cplusplus.in.One.Hour.a.Day.8th.Edition.

    展开全文
  • 深剖基类和派生类的虚函数表

    千次阅读 2018-03-31 15:31:53
    1、当派生类实现基类的虚函数时,基类中虚函数表和虚函数地址和派生类中虚函数表和虚函数地址不同;当派生类实现基类的虚函数时,基类中虚函数表和虚函数地址和派生类中虚函数表和虚函数的地址相同。1、派生类重新...

    1、当派生类实现基类的虚函数时,基类中虚函数表和虚函数地址和派生类中虚函数表和虚函数地址不同;

    当派生类不实现基类的虚函数时,基类中虚函数表和虚函数地址和派生类中虚函数表和虚函数的地址相同。

    1、派生类重新实现虚函数。查看其虚函数表和虚函数表中虚函数的地址 

    [cpp]  view plain  copy
    1. #include<iostream>  
    2. using namespace std;  
    3. class Base{  
    4.     public:   
    5.     virtual void fun()  
    6.     {  
    7.         cout<<"This is Base Class"<<endl;  
    8.     }  
    9. };  
    10. class Derived:public Base{  
    11.     public:  
    12.     void fun()  
    13.     {  
    14.         cout<<"This is Derived Class"<<endl;  
    15.     }  
    16. };  
    17. int main()  
    18. {  
    19.     Base B;  
    20.     Derived D;   
    21.     int **p=(int**)&B;  
    22.     cout<<"基类的虚函数表地址:"<<p[0]<<endl;  
    23.     cout<<"基类的虚函数表中虚函数的地址:0x"<<hex<<p[0][0]<<endl;  
    24.     p=(int**)&D;  
    25.     cout<<"派生类的虚函数表地址:"<<p[0]<<endl;  
    26.     cout<<"派生类的虚函数表中虚函数的地址:0x"<<hex<<p[0][0]<<endl;  
    27.       
    28.     return 0;  
    29. }  

    输出结果:
    基类的虚函数表地址:0x445060
    基类的虚函数表中虚函数的地址:0x415390
    派生类的虚函数表地址:0x445070
    派生类的虚函数表中虚函数的地址:0x4153dc
    可以看出,基类和派生类的虚函数表不同,虚函数的地址也不同。这个结果符合预期,因为派生类中重新实现了虚函数,基类肯定

    有自己的虚函数表,虚函数的地址自然是重新实现的那个。

    2、派生类不重新实现虚函数。查看其虚函数表和虚函数表中虚函数的地址 

    [cpp]  view plain  copy
    1. #include<iostream>  
    2. using namespace std;  
    3. class Base{  
    4.     public:   
    5.     virtual void fun()  
    6.     {  
    7.         cout<<"This is Base Class"<<endl;  
    8.     }  
    9. };  
    10. class Derived:public Base{  
    11.       
    12. };  
    13. int main()  
    14. {  
    15.     Base B;  
    16.     Derived D;   
    17.     int **p=(int**)&B;  
    18.     cout<<"基类的虚函数表地址:"<<p[0]<<endl;  
    19.     cout<<"基类的虚函数表中虚函数的地址:0x"<<hex<<p[0][0]<<endl;  
    20.     p=(int**)&D;  
    21.     cout<<"派生类的虚函数表地址:"<<p[0]<<endl;  
    22.     cout<<"派生类的虚函数表中虚函数的地址:0x"<<hex<<p[0][0]<<endl;  
    23.       
    24.     return 0;  
    25. }  
    26. 输出结果: 
    基类的虚函数表地址:0x445050
    基类的虚函数表中虚函数的地址:0x415390
    派生类的虚函数表地址:0x445060
    派生类的虚函数表中虚函数的地址:0x415390

    派生类虽然重新实现虚函数,但是派生类有自己的虚函数表,但是虚函数表中,虚函数的地址和基类中虚函数的地址一样。 

    3、一个类继承多个基类时,有一张虚函数表,多个虚函数指针。

    展开全文
  • 基类和派生类的虚函数表

    千次阅读 2014-07-31 10:50:37
    查看派生类是否和基类公用一个虚函数表,或是否使用相同的虚函数(没有重新实现的情况下)。
    在派生类中,其虚函数表和基类的虚函数表有什相关性吗?做个试验看一下: 

    1、派生类重新实现虚函数。查看其虚函数表和虚函数表中虚函数的地址 

    #include<iostream>
    using namespace std;
    class Base{
    	public: 
    	virtual void fun()
    	{
    		cout<<"This is Base Class"<<endl;
    	}
    };
    class Derived:public Base{
    	public:
    	void fun()
    	{
    		cout<<"This is Derived Class"<<endl;
    	}
    };
    int main()
    {
    	Base B;
    	Derived D; 
    	int **p=(int**)&B;
    	cout<<"基类的虚函数表地址:"<<p[0]<<endl;
    	cout<<"基类的虚函数表中虚函数的地址:0x"<<hex<<p[0][0]<<endl;
    	p=(int**)&D;
    	cout<<"派生类的虚函数表地址:"<<p[0]<<endl;
    	cout<<"派生类的虚函数表中虚函数的地址:0x"<<hex<<p[0][0]<<endl;
    	
    	return 0;
    }

    输出结果:
    基类的虚函数表地址:0x445060
    基类的虚函数表中虚函数的地址:0x415390
    派生类的虚函数表地址:0x445070
    派生类的虚函数表中虚函数的地址:0x4153dc
    可以看出,基类和派生类的虚函数表不同,虚函数的地址也不同。这个结果符合预期,因为派生类中重新实现了虚函数,基类肯定
    有自己的虚函数表,虚函数的地址自然是重新实现的那个。

    2、派生类不重新实现虚函数。查看其虚函数表和虚函数表中虚函数的地址 

    #include<iostream>
    using namespace std;
    class Base{
    	public: 
    	virtual void fun()
    	{
    		cout<<"This is Base Class"<<endl;
    	}
    };
    class Derived:public Base{
    	
    };
    int main()
    {
    	Base B;
    	Derived D; 
    	int **p=(int**)&B;
    	cout<<"基类的虚函数表地址:"<<p[0]<<endl;
    	cout<<"基类的虚函数表中虚函数的地址:0x"<<hex<<p[0][0]<<endl;
    	p=(int**)&D;
    	cout<<"派生类的虚函数表地址:"<<p[0]<<endl;
    	cout<<"派生类的虚函数表中虚函数的地址:0x"<<hex<<p[0][0]<<endl;
    	
    	return 0;
    }

    输出结果: 
    基类的虚函数表地址:0x445050
    基类的虚函数表中虚函数的地址:0x415390
    派生类的虚函数表地址:0x445060
    派生类的虚函数表中虚函数的地址:0x415390
    派生类虽然重新实现虚函数,但是派生类有自己的虚函数表,但是虚函数表中, 虚函数的地址和基类中虚函数的地址一样。 


    展开全文
  • 如何在派生类实现类的基本函数: 1, 首先要在派生类中的构造函数中调用基类的构造函数 2, 基类与派生类的析构函数一定要为虚函数 class Base { public: Base& operator=(const Base &base); virtual ~...
    如何在派生类中实现类的基本函数:
    

    1,  首先要在派生类中的构造函数中调用基类的构造函数

    2,  基类与派生类的析构函数一定要为虚函数

    class Base
    {
    public:
    	Base& operator=(const Base &base);
    	virtual ~Base()        //申明为虚函数
    	{
    		cout<<"~Base"<<endl;
    	}
    private:
    	int b_x, b_y, b_z;
    };
    
    class Derived: public Base
    {
    public:
    	Derived& operator=(const Derived &derived);
    	virtual ~Derived()     //申明为虚函数
    	{
    		cout<<"~Derived"<<endl;
    	}
    private:
    	int d_i, d_j, d_k;
    };
    
    Derived& Derived::operator=(const Derived &derived)
    {
    	if (this == &derived)
    	{
    		return *this;
    	}
    	Base::operator=(derived);    //调用基类的构造函数初始化基类成员变量
    	d_i = derived.d_i;
    	d_j = derived.d_j;
    	d_k = derived.d_k;
    	return *this;
    }
    int main(void)
    {
    	Base *p = new Derived;
    	delete p;
    	return 0;
    }

    运行结果:


    如果不申明为虚函数的话,那么就只能析构基类,不能析构派生类。


    展开全文
  • 派生类的构造函数

    千次阅读 2014-06-27 22:20:53
    基类的构造函数不能被派生类继承,所以派生类必须自己完成构造函数n
  • 5.1简单的派生类的构造函数派生类构造函数一般形式为派生类构造函数名(总参数):基类构造函数名(参数){派生类中新增数据成员初始化语句}总参数包括基类构造函数所需的参数和对派生类新增的数据成员初始化...
  • 想验证一下C++ 基类private纯虚函数派生类中是否可以实现,若可以,该怎么实现 a.先在网上搜到一下资源 1.【转】“纯虚函数可以设计成私有的,不过这样不允许在本类之外的非友元函数中直接调用它,子类中只有...
  • 题目:设计基类点类(Point)、直接派生类圆类(Circle)、间接派生类圆柱体类(Cylinder),将求面积的函数(area)声明成虚函数,并在主函数实现函数调用,输出点类、圆类和圆柱体类面积。提示:其他数据成员和...
  • 派生类的构造函数与析构函数 与一般成员函数不同,派生类并不继承基类的构造函数和析构函数。在创建派生类对象时,系统要调用派生类的构造函数。 由于派生类中包含从基类继承来的成员和派生类中新声明的数据...
  • 派生类继承了基类的成员,实现了代码的重复利用,但基类的构造函数和析构函数不能被继承。如果在派生类中需要对新增加的成员进行初始化,则需要加入派生类的构造函数。同样派生类也需要添加析构函数实现一些结束...
  • C++派生类的构造函数

    千次阅读 多人点赞 2018-07-17 14:15:53
    构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类的构造函数,当然更不能成为普通的成员函数。 在设计派生类时,对继承过来的成员变量的初始化工作也要由派生类的...
  • 派生类的目的是为了发展,派生类继承了积累的成员,实现了原有代码的重用,这只是一部分,而代码的扩充才是最主要的,只有通过添加新的成员,加入新的功能,类的派生才有实际意义。 派生类的构造函数只负责对新增的...
  • 这里添加了以B为直接基类的派生类D,仍以A类作为基类指针,但是最初只在B中声明的虚构函数的调用问题,明显,虚函数并没有起作用 这里添加了以B为直接基类的派生类D,以B类作为基类指针,但是最初只在B中声明的虚构...
  • 一、不能自动继承的成员函数 构造函数 析构函数 =运算符 二、继承与构造函数 基类的构造函数不被继承,派生类中需要声明自己的构造...派生类的构造函数需要给基类的构造函数传递参数  C++ Code  1 2 3 4
  • #include using namespace std; class A { public: A(){}; virtual ~A(){}; virtual int Show()=0; }; class B:public A { public: B(){}; virtual ~B(){}; }; class C:public B ...pub
  • 派生类的构造函数与析构函数的调用顺序 前面已经提到,构造函数和析构函数的调用顺序是先构造的后析构,后构造的先析构。 那么基类和派生类中的构造函数和析构函数的调用顺序是否也是如此呢? 构造函数的调用...
  • C++基类与派生类函数调用情况

    千次阅读 2014-04-17 11:26:31
    函数调用的时候,如果该函数在基类中被定义为虚函数,那么在调用的时候看该指针(包括基类指针和派生类指针)所指向的对象,如果是派生类的对象就调用派生类中重写的函数,如果是基类的对象就调用基类中的函数。...
  • 如何从派生类函数调用父类函数

    千次阅读 2020-01-09 14:17:27
    如何使用C ++从派生类调用父函数? 例如,我有一个名为parent的类,以及一个称为child的类,该类是从parent派生的。 每个类中都有一个print功能。 在定义孩子的打印功能时,
  • c++继承 基类 派生类函数

    千次阅读 多人点赞 2020-06-15 19:25:39
    派生类继承了基类除构造函数以外的所有成员。 继承的方式   继承方式有public(公有继承)、private(私有继承)和protected(保护继承)。基类中不同访问限定符下(public、protected、private)的成员以不同的...
  • 文章目录一、派生类构造函数与基类构造函数二、创建与销毁派生类对象时,构造函数和析构函数的调用三、派生类和基类之间的特殊关系四、公有继承(一)、何为公有继承(二)、多态公有继承(三)、虚函数的工作原理...
  • 第十五讲:派生类的构造函数和析构函数本讲基本要求 * 理解:派生的...一、 简单的派生类的构造函数一级派生类中定义构造函数一般形式为: 派生类构造函数名(总参数列):基类构造函数名(参数列) { 派生类中新增
  • 如何在派生类实现类的基本函数基类的构造函数、析构函数、赋值函数都不能被派生类继承。如果类之间存在继承关系,在编写上述基本函数时应注意以下事项:
  • C++继承派生类构造函数的写法

    千次阅读 2019-06-16 22:51:01
    C++有三大思想:抽象与封装、继承与派生、多态性,是c++开发人员面对对象编程必须掌握的知识。 初学者对子类继承中构造函数的写法有时会...①派生类构造函数先调用基类的构造函数 ②再执行派生类构造函数本身(...
  • 1、如果基类没有定义构造函数派生类也可以不定义构造函数,使用默认的构造函数,其新增成员的初始化可以用其他公有函数实现. 2.如果基类中定义了缺省构造函数或根本没有定义任何一个构造函数(此时,由编译器...
  • 在C++程序员的面试中,经常会出现派生类与基类的构造函数、析构函数的执行顺序。其实这是一个很基本的问题,没有什么难度,只需要记住就OK了。   1.派生类的构造函数和析构函数的执行顺序  首先执行基类的构造...
  • 派生类函数调用基类版本

    千次阅读 2012-12-04 10:27:02
    C++ primer 这本书上有这么两句话“派生类虚函数...当你实现派生类函数B : foo时,如果函数体内需要调用基类的虚函数版本时,需要显式使用基类的作用域操作符A::foo(),否则foo()就会在派生类作用域内调用派生类版
  • 实现方法也是老生常谈,通过每个对象中的虚函数表指针,去找属于自己类的虚函数执行。那如果用派生类指针指向基类然后调用虚函数呢? #include<iostream> #include<vector> using namespace std; ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 196,453
精华内容 78,581
关键字:

函数表实现派生类