精华内容
下载资源
问答
  • 2019-04-09 14:23:23

    1 问题

    在C++中,运行时多态是通过虚函数来实现的。本文将讨论关于虚函数实现多态的问题:

    • 相信大家都知道怎么使用虚函数实现多态,但是它的原理是什么呢?
    • 构造函数可以声明为虚函数吗?为什么?
    • 析构函数可以声明为虚函数吗?为什么?

    2 概念

    2.1 虚表和虚表指针

    要理解虚函数实现多态的原理,我们首先要知道 虚表虚表指针 的概念:

    • 含有虚成员函数的类称为虚类,如果一个类是虚类,那么编译器会自动为其添加一个虚表(虚函数表)和一个称为虚表指针(指向虚表的的指针,__vptr)的数据成员;

    虚表

    • 每个虚类,都有一个虚函数表;
    • 本质上是一个指针数组,其中元素为指向该类的虚成员函数的函数指针;
    • 属于类,为该类的所有对象所共用;(static?)
    • 在编译阶段就已经被确定了。(const?)

    虚表指针

    • 属于对象,是编译器自动添加的一个指针成员变量;
    • 虚表指针,在构造函数中初始化;

    2.2 虚函数调用过程

    现有基类对象指针p和基类虚函数func1

    class Base {
    public:
    	...
    	virtual void func1() {
    		...
    	}
    	...
    };
    int main() {
    	Base* p = new Base();
    	p->func1();
    	return 0;
    }
    

    在执行 “p->func1();” 时,主要步骤有:

    • 首先发现 p 是一个指针,且调用的函数 func1 是一个虚函数;
    • 此时会通过该对象的虚表指针 __ptr 访问到它的虚表,然后在虚表中查找虚函数func1所对应的函数指针;
    • 根据函数指针找到函数func1,并执行。

    3 虚函数实现多态原理

    现假设已有 Base 和 Derived 两个类,具体情况如下:

    #include <iostream>
    using namespace std;
    
    class Base {
    public:
    	virtual void func1() {
    		cout << "Base func1 called." << endl;
    	}
    	virtual void func2() {
    		cout << "Base func2 called." << endl;
    	}
    	void func3() {
    		cout << "Base func3 called." << endl;
    	}
    private:
    	int x;
    	int y;
    };
    class Derived : public Base {
    public:
    	virtual void func1() {
    		cout << "Derived func1 called." << endl;
    	}
    	virtual void func2() {
    		cout << "Derived func2 called." << endl;
    	}
    	virtual void func4() {
    		cout << "Derived func4 called." << endl;
    	}
    private:
    	int z;
    };
    

    基类Base具有三个成员函数,其中func1和func2为虚函数,func3为普通成员函数;派生类Derived对func1和func2进行了重写,并新添加了一个虚函数func4。以下为多态的示例代码:

    Base* ptrBase = new Derived();
    ptrBase ->func1();	//显然输出:Derived func1 called.
    ptrBase ->func2();	//显然输出:Derived func2 called.
    ptrBase ->func3();	//显然输出:Base func3 called.
    ptrBase ->func4();	//报错
    

    分析如下

    • 基类Base和派生类Derived都具有虚函数,均为虚类,因此都具有虚表和虚表指针。Base类的虚表vTableBase包含两个函数指针,第一个指向func1,第二个指向func2;Derived类的虚表vTableDerived包含三个函数指针,第一个指向func1,第二个指向func2,第三个指向func4。
    • 首先,“new Derived();” 会调用构造函数,生成一个Derived类对象的指针(ptrDerived),并使该对象的虚表指针指向Derived类的虚表;然后,使用ptrDerived对ptrBase的数据成员(当然也包括虚表指针 __ptr )进行初始化,使得ptrBase的虚表指针不再指向Base类的虚表,而是指向Derived类的虚表(实际上是Derived类虚表的子集,由于func4,不是Base的成员函数,所以该虚表中不会包含有func4的函数指针)即:此时 ptrBase所指对象的虚表依然包含2个函数指针,不过它们不再指向基类Base的成员函数func1 和 func2,而是指向派生类Derived的成员函数 func1 和 func2。
    • 结合虚函数的调用过程:首先,ptrBase 是一个对象指针,且 func1 是一个虚函数,然后根据该对象的虚表指针 __vptr,找到其所指的虚表,接着找到虚函数 func1 的函数指针,并对其执行。由于此时虚表中虚函数 func1 的函数指针指向派生类Derived的虚函数 func1 ,所以,执行的是派生类的虚函数 func1。

    4 构造函数可以声明为虚函数吗?

    显然构造函数是不能声明为虚函数的。
    我们知道,在调用虚函数前,需要先访问虚表指针,得到虚表,然后再执行虚表中相对应的函数。假设,现在将构造函数声明为虚函数:调用构造函数时,发现构造函数是一个虚函数,然后去访问虚表指针,可是虚表指针是在构造函数中进行初始化的,而目前构造并没有执行,也就是说,虚表指针还没有初始化,只是一个空值,理所当然的,也就找不到指向构造函数的函数指针,因此无法完成构造函数的调用。可见,构造函数是不能声明为虚函数的。

    5 析构函数可以声明为虚函数吗?

    1、当然是可以的,而且,为了防止内存泄漏,基类的析构函数必须声明为虚函数!
    2、为什么将基类析构函数声明为虚函数,就可以防止内存泄漏?

    • 如果没有将基类析构函数声明为虚函数,在释放指向派生类对象的基类指针的时候,只会调用基类的析构函数,而派生类的析构函数不会被调用,导致属于派生类的新添加的数据得不到释放,从而导致内存泄漏。
    • 如果将析构函数声明为虚函数,在释放指向派生类对象的基类指针的时候,会调用派生类的析构函数,而派生类的析构函数会自动调用基类的析构函数,从而释放所有内存,避免了内存泄漏。

    3、可是,有个问题,为什么将基类析构函数声明为虚函数之后,在释放指向派生类对象的基类指针时,调用的是派生类的析构函数?难道派生类的析构函数重写了基类的析构函数?不可能啊,基类析构函数和派生类析构函数的函数名不同,不能构成重写啊。

    • 其实,析构函数是一个特殊的函数,编译器在编译时,析构函数的名字统一为destucter;
    • 所以只要将基类的析构函数声明为虚函数,不管子类的析构函数前是否加virtual,都构成重写。这也就可以解释为什么将基类析构函数声明为虚函数,释放指向派生类对象的基类指针时,会调用派生类的析构函数,因为虚表中的函数指针指向的是派生类的析构函数。

    6 参考文献

    https://blog.csdn.net/lihao21/article/details/50688337(推荐,讲得很好)
    https://blog.csdn.net/han8040laixin/article/details/81704165

    更多相关内容
  • 但是我发现当碰到稍微复杂的多态问题的时候,就很难以理解其实现原理,导致使用出错,比如:一个派生类继承基类,生成对象有两种方式:调用基类生成对象、调用派生类生成对象,调用完毕后释放对象,哪种方式必须要用...

    刚开始学习C++虚函数的时候,只知道虚函数就是用来构成动态多态的,以及如何使用虚函数。但是我发现当碰到稍微复杂的多态问题的时候,就很难以理解其实现原理,导致使用出错,比如:一个派生类继承基类,生成派生类对象有两种方式:调用基类指针生成对象、调用派生类指针生成对象,调用完毕后释放对象,哪种方式必须要用虚函数实现基类和派生类的析构函数,如果不用会出现什么问题?(可移步基类的析构函数是否要定义为虚函数)。而《C++ Primer》中更多的是对虚函数使用的讲解,查阅有关虚函数实现多态的博客也大都千篇一律,这对学习者从底层理解虚函数实现多态的原理帮助甚微。本文将从内存角度上剖析一下虚函数实现多态的底层原理,希望能给C++学习者提供帮助。

    一、无继承时,含虚函数类的内存布局剖析

    无继承的类中定义虚函数实际上没有意义的,因为虚函数存在的意义就是为了实现动态多态,即将虚函数看作一个接口去调用基类和派生类中同一个函数实现不同的功能。但是为了更好地展示从无继承到有继承时虚函数引起的内存布局变化情况,这里首先定义一个无继承类进行分析。

    class Base
    {
    public:
    	virtual void fun1() {};
    	virtual void fun2() {};
    	virtual void fun3() {};
    	void fun4() {};
    
    private:
    	int m_A;
    	int m_B;
    };
    

    在vs2013中完成类定义后,选择“项目—>属性—>C/C++命令行—>其他选项”,在这里写上/d1 reportSingleClassLayoutBase,然后生成解决方案,输出行就会显示Base类的内存布局,如下图所示:
    在这里插入图片描述
    由图中可知,Base类的内存大小为12字节,首先存放的是虚表指针vfptr(占有4个字节),指向虚函数表vftable的首地址;接着按声明顺序依次存放类的变量m_A、m_B(各占有4个字节)。其中,虚函数表vftable按声明顺序依次存放类中定义的3个虚函数fun1、fun2、fun3的地址。我们发现,Base类的内存布局中并没有函数fun4,这是因为fun4是一个普通的成员函数,在类定义的时候就会存储在代码区,所以不在Base类的内存布局中。
    注意:在设置“项目—>属性—>C/C++命令行—>其他选项”时,若要查看项目中所有类的内存布局,就写上"/d1 reportAllClassLayout";若查看类XXX的内存布局时,就写上"/d1 reportSingleClassLayoutXXX"。

    二、单一继承时,含虚函数类的内存布局剖析

    定义一个Child类继承Base类,类的定义如下:

    class Child :public Base
    {
    public:
    	virtual void fun1() {};
    	virtual void fun5() {};
    
    private:
    	int m_C;
    };
    

    选择“项目—>属性—>C/C++命令行—>其他选项”,修改为/d1 reportSingleClassLayoutChild,生成解决方案,输出行就会显示Child类的内存布局,如下图所示:
    在这里插入图片描述
    由图中可知,Child类的内存大小为16个字节,首先存放的是基类(Base类)的内存布局,依次为继承的虚表指针vfptr、变量m_A、变量m_B(均为4个字节);接着存放的是派生类(Child类)的内存布局,即m_C,如有多个变量,则按照声明顺序依次存放。最后,我们可看到虚表指针vfptr指向的虚函数表已变为Child类作用域下,&Child::fun1为类Child中重写函数fun1的地址,覆盖了原来的&Base::fun1, &Base::fun2 、 &Base::fun3依旧为基类中函数fun2、fun3的地址不变,&Child::fun5为类Child新定义的函数fun5的地址。

    三、利用虚函数实现多态

    分析了含虚函数的基类和派生类的内存布局之后,接着一起看看如何利用虚函数实现多态。依旧用上述的类Child继承类Base,并给虚函数fun1体中写入不同的内容,代码如下:

    #include<iostream>
    using namespace std;
    
    class Base
    {
    public:
    	virtual void fun1() { cout << "我是父亲" << endl; };
    	virtual void fun2() {};
    	virtual void fun3() {};
    	void fun4() {};
    
    protected:
    	int m_A;
    	int m_B;
    };
    
    class Child :public Base
    {
    public:
    	virtual void fun1() { cout << "我是儿子" << endl; };
    	virtual void fun5() {};
    private:
    	int m_C;
    };
    
    int main()
    {
    	Base* b;
    	b = new Base;  //b指向一个Base对象
    	b->fun1();
    
    	b = new Child;  //b指向一个Child对象
    	b->fun1();
    
    	system("pause");
    	return 0;
    }
    

    输出结果为:
    在这里插入图片描述
    从图中可以看到,当基类指针b指向基类(Base类)对象时,就会执行基类中的fun1函数体,当基类指针指向派生类(Child类)对象时,就会执行派生类中的fun1函数体,就形成了多态。同时,在代码测试中发现,基类指针b只能访问Child类中同基类共有的虚函数(fun1),而无法访问Child类中的其它成员函数(fun5)以及成员变量(m_C)。

    接着,一起分析一下案例中多态是如何实现的?基类指针b指向基类Base对象时,由Base类的内存布局可知,Base对象中有一个指向虚函数表的指针vfptr,当执行b->fun1()时,vfptr会指向虚表中fun1的地址(即&Base::fun1()),就会执行Base::fun1(),输出结果“我是父亲”。由Child类的内存布局可知,Child类中同样有一个指向本类中虚函数表的指针vfptr。基类指针指向派生类Child对象时,对象类型会被转换为Base类,但对象类型转换并不会改变当前对象中vfptr指向的虚表,当再次执行b->fun1()时,此时vfptr指向虚表中fun1的地址仍为&Child::fun1() ,输出结果为“我的儿子”。由此可见,多态的实现是采用迟绑定的,即编译器在编译的时候发现fun1是虚函数,就不会确定调用的函数版本,而是在实际运行时根据对象的类型来调用对应的fun1函数体。

    虚函数实现多态原理:当派生类继承基类时,在基类中利用virtual关键字定义若干个虚函数,会生成基类的虚表A,表中存放着所有虚函数的地址,而在派生类中重写某个虚函数func1时,派生类的的虚表B中,会用重写的虚函数地址覆盖原来的函数func1的地址,其它虚函数地址不变。程序采用迟绑定的编译模式,当基类指针指向基类对象时,基类对象的vptr指向虚表A,就会运行基类的func1;而基类指针指向派生类对象时,派生类对象的vptr指向虚表B,就会运行派生类的func1。这样,根据基类指针指向不同的对象,进而调用不同的函数体,就会有不同的表现形式,即实现多态。
    多态实现的详细原理可参阅:https://blog.csdn.net/fightHHA/article/details/81626383

    四、利用纯虚函数实现多态

    (1)纯虚函数是在基类中只声明不定义的虚函数,提供多态实现的接口,其声明方式为“virtual void function()=0”。
    (2)含有纯虚函数的基类是纯虚基类,不能生成对象。
    (3)派生类中必须对基类中声明的纯虚函数进行定义,否则无法编译。

    纯虚函数使用情况:
    在很多情况下,基类本身生成对象是不合情理的,这时就要在基类中声明一个纯虚函数,将基类变为一个抽象类,就无法生成基类对象。 例如,动物作为一个基类可以派生出小狗、小猫等派生类,但动物本身生成对象明显不合常理,因此将动物类定义为一个抽象类,就无法生成动物类对象。代码如下:

    #include<iostream>
    using namespace std;
    
    class Animal
    {
    public:
    	virtual void fun() = 0;  //纯虚函数
    };
    
    class dog:public Animal
    {
    public:
    	virtual void fun() { cout << "我是小狗" << endl; }
    };
    
    class cat :public Animal
    {
    public:
    	virtual void fun() { cout << "我是小狗" << endl; }
    };
    
    int main()
    {
    	Animal* animal;
    	//animal = new Animal;  //提示:不允许使用抽象类类型"Animal"的对象
    
    	animal = new dog;
    	animal->fun();
    
    	animal = new cat;
    	animal->fun();
    
    	system("pause");
    	return 0;
    }
    

    输出结果如下:
    在这里插入图片描述
    由代码和图可知,纯虚函数和虚函数的作用一样都是为了实现多态,区别就是无法生成抽象基类本身的对象。

    展开全文
  • 2、虚函数实现多态原理 当一个类中出现虚函数或着子类继承了虚函数时,就会在该类中产生一个虚函数表(virtual table),虚函数表实际上是一个函数指针数组(在有的编译器作用下是链表),里面的每一个元素对应...

    1、C++中如何实现多态

    • 基类中先声明一个虚函数
    • 至少有一个继承该基类的子类

    2、虚函数实现多态的原理

    • 当一个类中出现虚函数或着子类继承了虚函数时,就会在该类中产生一个虚函数表(virtual table),虚函数表实际上是一个函数指针数组(在有的编译器作用下是链表),里面的每一个元素对应指向该类中的某一个虚函数的指针。被该类声明的对象会包含一个虚函数表指针(virtual table pointer),指向该类的虚函数表的地址
    • 虚函数的调用过程: 当一个对象要调用到虚函数时,先将对象内存中的vptr指针(虚函数表指针)指向定义该类的vtbl(虚函数表),vtbl再寻找里面的指针指向想要调用的虚函数,从而完成虚函数的调用。
      在这里插入图片描述

    2.1 单类继承

    • 定义一个父类
    class Person{
    public:
    	virtual void f(){cout << "use f()" << endl;}
    	virtual void g(){cout << "use g()" << endl;}
    	virtual void h(){cout << "use h()" << endl;}
    };
    

    父类对象其在内存中布局如下:
    在这里插入图片描述

    • 再定义一个子类,此时并不覆盖父类的虚函数:
    class Bag:public Person{
    public:
    	virtual void i(){cout << "use i()" << endl;}
    	virtual void j(){cout << "use j()" << endl;}
    };
    

    在这里插入图片描述

    可以看出虚函数表内的虚函数是按声明顺序进行排序的
    父类虚函数排在子类虚函数之前

    • 当我们把子类中的虚函数覆盖掉:(修改Bag类)
    class Bag:public Person{
    public:
    	void f(){cout << "class Bag use fun" << endl;}
    	virtual void i(){cout << "use i()" << endl;}
    	virtual void j(){cout << "use j()" << endl;}
    }; 
    

    在这里插入图片描述
    子类覆盖的虚函数,放在父类原先放该虚函数的位置上。所以当父类指针指向该子类对象时,会调用该子类的重载函数

    2.2 多类继承

    • 子类没有覆盖父类的虚函数
      在这里插入图片描述
      子类的虚函数放在第一张虚函数表中,紧跟着第一个父类的虚函数
      如果每个父类都有虚函数,则有几个父类就有几张虚函数表

    • 子类覆盖父类的虚函数
      在这里插入图片描述
      父类的虚函数被子类覆盖后,则该子类对应的重载函数的位置在被覆盖的父类函数的位置上。(如果父类没有该虚函数,则不用被覆盖)
      父类的虚函数被子类覆盖后,则父类指针指向该子类对象时,调用的f()便是子类中重载的f()

    示例:

    #include <iostream>
    using namespace std;
    
    class Person1{
    public:
        virtual void f(){}
        virtual void g(){}
        virtual void h(){}
        virtual ~Person1(){}
    };
    
    class Person2{
    public:
        virtual void f(){}
        virtual void g(){}
        virtual void h(){}
        void a(){           // 成员函数,不需要重载
            cout << "class Person2" << endl;
        }
        virtual ~Person2(){}
    };
    
    class Person3{
    public:
        virtual void g(){}
        virtual void h(){}
        virtual ~Person3(){}
    };
    
    class Bag:public Person1, public Person2, public Person3{
    public:
        void f(){
            cout << "Bag f()" << endl;
        }
        void g(){
            cout << "Bag g()" << endl;
        }
        void a(){
            cout << "Class Bag" << endl;
        }
    };
    
    int main(int argc, char const *argv[])
    {
        Person3* p3 = new Bag;
        //p3->f();    // P3 没有成员函数f()
                      // 多态首先得是 父类有虚函数,其次是子类要定义该函数的重载
                      // 如果父类的虚函数改为成员函数,则子类无法进行重载,即无法实现多态
        delete p3;
        p3 = NULL;
    
        Person1* p1 = new Bag;
        p1->f();
        delete p1;
        p1 = NULL;
    
        Person2* p2 = new Bag;
        p2->a();
        delete p2;
        p2 = NULL;
        
        return 0;
    }
    
    
    展开全文
  • } 内部的实现原理可参考:虚函数实现原理 c++语言虚函数实现多态原理(更新版) 虚函数表的原理 #include using namespace std; //父类 class Base { public: virtual void f() { cout ()" ; } virtual void g() ...
    // virtualClass.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <iostream>
    
    using namespace std;
    class Base
    {
    public:
    	virtual void f(){ cout << "Base::f()" << endl; };
    	void g(){ cout << "Base::g()" << endl; };
    	void h(){ cout << "Base::h()" << endl; };
    };
    
    class Derive:public Base
    {
    public:
    	virtual void f(){ cout << "Derive::f()" << endl; };
    	void g1(){ cout << "Derive::g1()" << endl; };
    	void h1(){ cout << "Derive::h1()" << endl; };
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	Base *p = new Derive();
    	Base *p1 = new Base();
    	p->f();
    	p1->f();
    	return 0;
    }
    

    在这里插入图片描述

    内部的实现原理可参考:虚函数实现原理
    c++语言虚函数实现多态的原理(更新版)

    • 虚函数表的原理
    #include <iostream>
    using namespace std;
    
    //父类
    class Base
    {
    public:
    	virtual void f() { cout << "Base::f()" << endl; }
    	virtual void g() { cout << "Base::g()" << endl; }
    	virtual void h() { cout << "Base::h()" << endl; }
    };
    class Derive :public Base
    {
    	virtual void g() { cout << "Derive::g()" << endl; }
    };
    
    int main()
    {
    	//继承关系作用下虚函数的手工调用			
    	cout << sizeof(Base) << endl;
    	cout << sizeof(Derive) << endl;
    
    	Derive *d = new Derive(); //派生类指针。
    	long *pvptr = (long *)d;  //指向对象的指针d转成了long *类型。
    	long *vptr = (long *)(*pvptr); //(*pvptr) 表示pvptr指向的对象,也就是Derive本身。Derive对象是4字节的,代表的是虚函数表指针地址。
    
    	for (int i = 0; i <= 4; i++) //循环5次;
    	{
    		printf("vptr[%d] = 0x:%p\n", i, vptr[i]);
    	}
    
    	typedef void(*Func)(void); //定义一个函数指针类型
    	Func f = (Func)vptr[0]; //f就是函数指针变量。 vptr[0]是指向第一个虚函数的。
    	Func g = (Func)vptr[1];
    	Func h = (Func)vptr[2];
    
    	f();
    	g();
    	h();
    	//i();
    
    	Base *dpar = new Base();
    	long *pvptrpar = (long *)dpar;
    	long *vptrpar = (long *)(*pvptrpar);
    
    	for (int i = 0; i <= 4; i++) //循环5次;
    	{
    		printf("vptr Base[%d] = 0x:%p\n", i, vptrpar[i]);
    	}
    
    	Func fpar = (Func)vptrpar[0];
    	Func gpar = (Func)vptrpar[1];
    	Func hpar = (Func)vptrpar[2];
    
    	cout << "--------------------" << endl;
    	fpar();
    	gpar();
    	hpar();
    
    	return 1;
    }
    
    
    

    在这里插入图片描述

    展开全文
  • 自上一个帖子之间跳过了一篇总结性的帖子,之后再发,今天主要研究了c++语言当中虚函数多态实现,感叹于c++设计者的精妙绝伦 c++中虚函数表的作用主要是实现多态的机制。首先先解释一下多态的概念,多态是c++...
  • c++中虚函数表的作用主要是实现多态的机制。首先先解释一下多态的概念,多态是c++的特点之一,关于多态,简而言之就是用父类的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数,这种方法呢,可以...
  • 虚函数多态实现原理

    千次阅读 2019-09-07 18:00:07
    C++ 中的虚函数的作用主要是实现多态的机制。关于多态,说白了就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数(当然引用也可以达到该目的,引用也是指针的另一种变种)。这种技...
  • 出处:https://www.cnblogs.com/xgmzhna/p/10934562.html 转载于:https://www.cnblogs.com/legenBlog/p/10945382.html
  • 动态多态是用虚函数机制实现的,在运行期间动态绑定。举个例子:一个父类类型的指针指向一个 子类对象时候,使用父类的指针去调用子类中重写了的父类中的虚函数的时候,会调用子类重写 过后的函数,在父类中声明为加...
  • c++虚函数多态

    2018-10-03 12:03:53
    虚函数表(虚表)—多态原理 先看以下这个代码 class person { public: virtual void display() { cout 买全价价票" ; } }; class student:public person { public: virtual void display() { cout ...
  • c++ 深入理解虚函数 为什么使用虚函数?什么是虚函数虚函数是为了解决什么问题? 面向对象的三大特征: 封装 多态 继承 普通虚函数 虚析构函数 纯虚函数 抽象类 接口类 隐藏 vs 覆盖 隐藏与覆盖之间的...
  • 自上一个帖子之间跳过了一篇总结性的帖子,之后再发,今天主要研究了c++语言当中虚函数多态实现,感叹于c++设计者的精妙绝伦 c++中虚函数表的作用主要是实现多态的机制。首先先解释一下多态的概念,多态是c++...
  • 虚函数机制作为C++面向对象的重要支撑,但是我们对它知之甚少,因为它由编译器实现。今天就对虚函数进行整理,这样出去吹牛会更有底气。 1、虚函数的支持原理 每一个拥有虚函数的类会产生出一堆指向virtual ...
  • c++ 虚函数实现多态原理

    千次阅读 2014-08-15 12:46:26
    前面的文章说过了c++如何实现多态,最主要的就是使用虚函数,另一种方法就是RTTI,这里我们不做说明了。前面说过编译器是这样实现晚绑定的:编译器对每一个含有virtual函数的类创建一个虚函数表vtable,其实vtable...
  • 虚函数多态 ============================================== 1.多态的概念 字面上理解:多种表现形式 专业术语:C++允许父类的指针或者父类引用指向不同的子类对象,通过这个指针或者引用去调用不同子类的同名...
  • 目录多态多态的概念多态的构成条件虚函数虚函数的重写协变(返回值不同)析构函数的重写(函数名不同)final和overridefinaloverride抽象类多态原理 多态 多态的概念 什么是多态呢?就是一种事物,多种形态。就是...
  • C++ 中的虚函数多态

    2020-11-05 16:05:24
    C++ 中的虚函数的作用主要是实现多态的机制。关于多态,说白了就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数(当然引用也可以达到该目的,引用也是指针的另一种变种)。这种技...
  • 多态在C++中表现为,通过基类指针指向其派生类对象,用该指针调用基类中声明的虚函数,编译器可以自动根据该对象类别来确定实际调用的函数。可以通过以下例子说明: //demo1 #include using namespace std; class...
  • http://blog.csdn.net/leo115/article/details/8035078 上面是大牛的博客,他的其他内容也可以看看
  • 当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。 先看一个示例: 下面的实例中,基类 Shape 被派生为两个类,如下所示: #include <iostream> using namespace std; class Shape { ...
  • 多态实现原理刨析 虚函数关键字:virtual 未写virtual关键字前: #include<iostream> using namespace std; class Animal { public: void speak() { cout << "动物在说话" << endl; } };...
  • 首先介绍一下为什么会引进多态呢,基于c++的复用性和拓展性而言,同类的程序模块进行大量重复,是一件无法容忍的事情,比如我设置了苹果,香蕉,西瓜类,现在想把这些东西都装到碗这个函数里,那么在主函数当中,...
  • C++的 多态 面向对象有三个基本特征:封装、继承、多态。其中,封装可以使得代码模块化,忽略或者隐藏实现细节,优化整个程序的结构;继承可以扩展已存在的代码模块(类),...虚函数: 用virtual关键字申明的函数 纯虚
  • 1.示例代码 ...因此,可以通过在不同派生类中加override关键字进行重写的方式实现多态的效果。 2.示例代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; usin...
  • 我们知道C++动态多态是用虚函数实现的,而虚函数的实现方式虽说C++标准没有要求,但是基本都是用虚函数表实现的(编译器决定)。所以我们有必要了解一下虚函数表的实现原理。 用virtual关键字声明的成员函数是虚...
  • 多态实现效果:多态实现了同样的调用语句具有不同的表现形态。 多态成立的三个条件:继承、徐函数重写、父类指针指向子类对象。 多态的C++实现方法:virtual关键字,告诉编译器要执行多态;不要根据指针类型来...
  • 1.1虚函数实现多态 通过基类指针只能够访问派生类的成员变量,不能够访问派生类的成员函数。 解决问题的办法:使用虚函数(virtual function),只需要在函数声明前面增加virtual关键字。看下面的代码。 #include ...
  • 面试题目整理 虚函数多态

    千次阅读 2017-03-16 10:09:51
    C++中的虚函数的作用主要是实现多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,744
精华内容 7,897
关键字:

虚函数实现多态的原理