精华内容
下载资源
问答
  • Cpp-虚函数

    千次阅读 2017-08-29 15:41:57
    虚函数,虚析构函数,纯虚函数,抽象类 虚函数 定义:函数前加virtual,例子void ...一般来说父类的函数被子类函数重写必须采用虚函数。 class Shape { public: virtual double calcArea(){...}//虚函数 ....
    虚函数,虚析构函数,纯虚函数,抽象类
    虚函数
    定义:在函数前加virtual,例子void virtual demo();
    作用:多态的重要部分
    一般来说父类中的函数被子类函数重写必须采用虚函数。
    class Shape
    {
    public:
        virtual double calcArea(){...}//虚函数
        ....                                      //其他部分
    private:
        ....
    };
    ....
    class Circle:public Shape
    {
    public:
        Circle(double r);
        virtual double calcArea();//此处的virtual不是必须的,如果不加,系统会自动加
                                            //上,如果加上则会在后续的时候看的比较明显(推荐加上)
        ....
    private:
        ....
    };
    ....
    class Rect:public Shape
    {
        Rect(double width,double height);
        virtual double calcArea();
    private
        ....
    };
    ....
    虚函数在使用中的限制(重要):
    • 普通函数不能是虚函数,也就是说这个函数必须是某一个类的成员函数,不可以是一个全局函数,否则会导致编译错误。
    • 静态成员函数不能是虚函数 static成员函数是和类同生共处的,他不属于任何对象,使用virtual也将导致错误。
    • 内联函数不能是虚函数 如果修饰内联函数 如果内联函数被virtual修饰,计算机会忽略inline使它变成存粹的虚函数。
    • 构造函数不能是虚函数,否则会出现编译错误
    虚函数的实现:

           虚函数表指针:类中除了定义的函数成员,还有一个成员是虚函数表指针(占四个基本内存单元),这个指针指向一个虚函数表的起始位置,这个表会与类的定义同时出现,这个表存放着该类的虚函数指针,调用的时候可以找到该类的虚函数表指针,通过虚函数表指针找到虚函数表,通过虚函数表的偏移找到函数的入口地址,从而找到要使用的虚函数。

            当实例化一个该类的子类对象的时候,(如果)该类的子类并没有定义虚函数,但是却从父类中继承了虚函数,所以在实例化该类子类对象的时候也会产生一个虚函数表,这个虚函数表是子类的虚函数表,但是记录的子类的虚函数地址却是与父类的是一样的。所以通过子类对象的虚函数表指针找到自己的虚函数表,在自己的虚函数表找到的要执行的函数指针也是父类的相应函数入口的地址。

            如果我们在子类中定义了从父类继承来的虚函数,对于父类来说情况是不变的,对于子类来说它的虚函数表与之前的虚函数表是一样的,但是此时子类定义了自己的(从父类那继承来的)相应函数,所以它的虚函数表当中管于这个函数的指针就会覆盖掉原有的指向父类函数的指针的值,换句话说就是指向了自己定义的相应函数,这样如果用父类的指针,指向子类的对象,就会通过子类对象当中的虚函数表指针找到子类的虚函数表,从而通过子类的虚函数表找到子类的相应虚函数地址,而此时的地址已经是该函数自己定义的虚函数入口地址,而不是父类的相应虚函数入口地址,所以执行的将会是子类当中的虚函数。这就是多态的原理。

    函数的覆盖和隐藏

    父类和子类出现同名函数称为隐藏。

    • 父类对象.函数函数名(...);     //调用父类的函数
    • 子类对象.函数名(...);           //调用子类的函数  
    • 子类对象.父类名::函数名(...);//子类调用从父类继承来的函数。

    父类和子类出现同名虚函数称为覆盖

    • 父类指针=new 子类名(...);父类指针->函数名(...);//调用子类的虚函数。
    虚析构函数

    [:->虚析构函数的特点:

    • 当我们在父类中通过virtual修饰析构函数之后,通过父类指针指向子类对象,通过delete接父类指针就可以释放掉子类对象

    [:->理论前提:

    • 执行完子类的析构函数就会执行父类的析构函数

    原理:

            如果父类当中定义了虚析构函数,那么父类的虚函数表当中就会有一个父类的虚析构函数的入口指针,指向的是父类的虚析构函数,子类虚函数表当中也会产生一个子类的虚析构函数的入口指针,指向的是子类的虚析构函数,这个时候使用父类的指针指向子类的对象,delete接父类指针,就会通过指向的子类的对象找到子类的虚函数表指针,从而找到虚函数表,再虚函数表中找到子类的虚析构函数,从而使得子类的析构函数得以执行,子类的析构函数执行之后系统会自动执行父类的虚析构函数。这个是虚析构函数的实现原理。

    纯虚函数

    class Shape
    {
    public:
        virtual  double calcArea()//虚函数
        {....}
        virtual  double calcPerimeter()=0;//纯虚函数
        ....
    };
    纯虚函数只提供一个接口,基类不实现纯虚函数

    抽象类

    含有纯虚函数的类

    接口类
    1.没有任何数据成员
    2.仅有成员函数
    3.成员函数都是纯虚函数

    注意:若父类有虚函数,则必须实现否则无法实例化,抽象类子类只有把抽象类当中的所有的纯虚函数都做了实现才可以实例化对象。







    展开全文
  • 因为多态时,父类调用虚函数的过程如下: (1)使用 this 指针找到虚函数表指针; (2)通过虚函数表指针获取到虚函数表。 (3)通过指针偏移获取实际的虚函数的指针。 (4)通过虚函数指针完成调用。 所以根据...

    因为在多态时,父类调用虚函数的过程如下:

    (1)使用 this 指针找到虚函数表指针;

    (2)通过虚函数表指针获取到虚函数表。

    (3)通过指针偏移获取实际的虚函数的指针。

    (4)通过虚函数指针完成调用。

    所以根据上述步骤,若没有 this 指针,第(1)步就无法执行,也就无从谈起多态。

    链接: 参考文章链接.

    展开全文
  • 由于编译期间编译器为每个类创建好了 vtbl,并且编译器会类的构造函数插入将虚函数表的地址赋值给虚函数表指针的隐藏代码,所以对象只有运行期间才能获取到虚函数表指针的内容。 (SAW:Game Over!) .....

    一、虚函数表

           在编译期间创建。编译器会为每个类确定好虚函数表(vtbl)的内容。

    二、虚函数表指针

           虚函数表指针跟随着对象,在运行期间创建。由于在编译期间编译器为每个类创建好了 vtbl,并且编译器会在类的构造函数中插入将虚函数表的地址赋值给虚函数表指针的隐藏代码,所以对象只有在运行期间才能获取到虚函数表指针的内容。

     

    (SAW:Game Over!)

    展开全文
  • 用一个示例介绍虚函数表指针访问虚函数,更易于方便理解虚函数,程序也有注释// virtual-Table.cpp #include <iostream> using namespace std; class A { public: A() { cout <&lt...

    在C++中随处可见封装,继承,多态。

    多态的实现,是基于虚函数的继承,虚函数则是基于虚函数表和虚函数表指针。

    用一个示例介绍虚函数表指针访问虚函数,更易于方便理解虚函数,程序中也有注释

    // virtual-table.cpp
    #include <iostream>
    
    using namespace std;
    
    class A {
    public:
    	A() {
    		cout << __func__ << endl;
    	}
    
    	virtual void fun() {
    		cout << "A : " << __func__ << endl;
    	};
    
    	virtual void bar() {
    		cout << "A : " << __func__ << endl;
    	};
    
    };
    
    class B : public A {
    public:
    	B() : A() {
    		cout << __func__ << endl;
    	}
    
    	void fun() {
    		cout << "B : " << __func__ << endl;
    	}
    
    	void bar() {
    		cout << "B : " << __func__ << endl;
    	}
    
    };
    
    
    int main (int argc, char *argv[])
    {
    	typedef void (*pfun) (void);
    	
    	int bits = sizeof(int *);
    
    	B b;
    	B b1;
    
    	cout << "-------- 虚函数表 -----------" << endl;
    	// 虚表地址存在于每个实例对象的首地址处
    	// 虚函数表地址是同一个地址,说明虚表只属于该类
    	// 不属于该类的实例子对象
    	cout << *(int *)*(int *)&b << endl;
    	cout << *(int *)*(int *)&b1 << endl;
    
    	pfun fun = NULL;
    	pfun fun1 = NULL;
    	
    	cout << "----- 利用虚表调用函数 ------" << endl;
    	fun = (pfun)*((int *)*(int *)&b);
    	fun();
    	if (8 == bits) {
    		fun = (pfun)*((int *)*(int *)&b + 2);
    	}
    	else if (4 == bits) {
    		fun = (pfun)*((int *)*(int *)&b + 1);
    	}
    	fun();
    
    	fun1 = (pfun)*((int *)*(int *)&b);
    	fun1();
    	if (8 == bits) {
    		fun1 = (pfun)*((int *)*(int *)&b + 2);
    	}
    	else if (4 == bits) {
    		fun1 = (pfun)*((int *)*(int *)&b + 1);
    	}
    	fun1();
    
    	// 多态
    	cout << "---------- 指针 -------------" << endl;
    	A *a = new B;
    	a->fun();
    	
    	cout << "---------- 引用 -------------" << endl;
    	A &a1 = b;
    	a1.bar();
    
    	return 0;
    }

    编译,运行

    root@root $ g++ virtual-table.cpp
    root@root $ ./a.out 
    A
    B
    A
    B
    -------- 虚函数表 -----------
    4197940
    4197940
    ----- 利用虚表调用函数 ------
    B : fun
    B : bar
    B : fun
    B : bar
    ---------- 指针 -------------
    A
    B
    B : fun
    ---------- 引用 -------------
    B : bar
    

    展开全文
  • 当类声明虚函数时,编译器会生成一个虚函数表,虚函数表是一个存储成员函数指针的数据结构。 虚函数表是由编译器自动生成与维护的,virtual成员函数会被编译器放入虚函数,当存在虚函数时,每个对象都...
  • (声明:该文章转自Fiona的blog)1、虚函数 ...or proteceted, 但是对于多态来说,没有意义),基类的类定义定义虚函数的一般形式: virtual 函数返回值类型 虚函数名(形参表) ...
  • CPP多态性与虚函数

    2020-05-14 01:55:59
    文章目录多态性与虚函数面向对象程序设计的多态性派生类与基类对象之间的赋值虚函数虚析构函数纯虚函数(抽象类)虚函数与虚基类派生类重定义基类的重载函数虚函数动态绑定的实现原理 多态性与虚函数 面向对象...
  • CPP-基础:虚函数

    2019-10-08 13:04:51
    虚函数表  对C++了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数...这样,虚函数的类的实例这个表被分配了这个实例的内存,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表...
  • Cpp--虚函数的存在

    2015-11-09 14:01:42
    1.虚函数基础: 定义:某基类声明为 virtual 并一个或多个派生类被重新定 义的成员函数。...2.1 非类的成员函数不能定义为虚函数,类的成员函数静态成员函数和构造函数也不能定义为虚函数
  • C++对象内存布局--③测试多继承派生类的虚函数在哪一张虚函数...//测试多继承派生类的虚函数在哪一张虚函数表.cpp //2010.8.18 //测试证明派生类的虚函数的地址跟第一基类的虚函数地址保存在同一张虚函数表...
  • 这里唯一想说明的一点就是,使用虚函数继承时,当继承类被强转成基类后调用虚函数,调用的还是继承类的虚函数。而重载方式的继承类被强转成基类再调用重载函数,则调用的是基类的函数。废话不多说,上代码: ...
  • 之后新发布的so中在原有头文件的虚函数A前面增加了一个虚函数B定义; 应用如果直接使用新的so进行替换,不重新编译的情况下会造成虚函数偏移错位。即原应用调用的A的地方,会变成调用B; 基类指针指向派生类; ...
  • #include <iostream> #include <stdlib.h> #include <string> using namespace std; class father{ public: virtual void func(){cout << "father func() "<... void
  • 对象的构造函数插入向 vptr 赋值虚函数表的首地址的代码。 若是多重继承,每个父类均有虚函数,那么子类会继承每一个父类的 vptr。子类若也有虚函数,则将该虚函数的地址添加到第一个父类的虚函数。 析构...
  • // Virtual.cpp : 定义控制台应用程序的入口点。 //#include "stdafx.h" #include using namespace std; class Base { public: virtual void f() { cout ()" ; } virtual void g()
  • 7. 析构函数也不要调用虚函数析构的时候会首先调用子类的析构函数,析构掉对象的子类部分,然后调用基类的析构函数析构基类部分,如果基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类...
  • 虚函数(Virtual Function):基类声明为 virtual 并一个或多个派生类被重新定义的成员函数。 纯虚函数(Pure Virtual Function):基类没有实现体的虚函数称为纯虚函数(有纯虚函数的基类称为虚基类)。
  • 转自:... 1.虚函数 一般类的布局 [cpp] view plaincopyprint? class A { public: int m_pbl; protected: int m_prt; private: int m_p
  • C++ 深入虚函数

    2020-08-05 21:01:03
    文章目录编程环境:虚函数表验证:类成员的空间位置: 简 述: 对于 C++ 的多次继承后,其中含有虚函数的时候,探究一下其中的虚函数表;以及其变量内存的分布情况。 编程环境: ????: Win10 2004 ???? ...
  • // TestConsole.cpp : 定义控制台应用程序的入口点。 // #include using namespace std; //class A class A { public: A() { cout; } virtual ~A() { cout; } void f
  • C++虚函数

    2016-01-13 15:08:52
    就是有父子关系的类各创建一张虚函数表,而不是每个实例创建一个;每个实例一个虚函数的指针会指向虚函数表,而从完成调用。 具体可参见: http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/
  • 构造函数不能是虚函数,因为调用构造函数创建对象时,构造函数必须是确定的,所以构造函数不能是虚函数。析构函数可以是虚函数。1.父类Father.h: 代码如下:#pragma onceclass Father{public: Father(void); ...
  • 虚函数是应派生类重新定义的成员函数。 当使用指针或对基类的引用来引用派生的类对象时,可以为该对象调用虚函数并执行该函数的派生类版本。 虚函数确保为该对象调用正确的函数,这与用于进行函数调用的表达式...
  • 虚函数和纯虚函数的区别? 虚函数 引入原因:为了方便使用多态特性,我们常常需要在基类中定义虚函数。 纯虚函数在基类中是没有定义的,... 直接=0 不要 在cpp中定义就可以了。 纯虚函数相当于接口,不能直接...
  • 1、在一个类中定义一个纯虚函数,则这个类是抽象类。纯虚函数在基类中是不实现的,只是提供一个接口。在子类中分别去实现。... 不要 在cpp中定义;纯虚函数相当于接口,不能直接实例化,需要派...
  • // c_datastructure.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include #include using namespace std; class Base { public: Base() { fun(); } virtual void fun() { cout ;
  • //直接=0 不要 在cpp中定义就可以了。 纯虚函数相当于接口,不能直接实例化,需要派生类来实现函数定义。 虚函数在子类里面也可以不重载的;但纯虚必须在子类去实现, 普通成员函数是静态编译的,没有运行
  • /// @brief 构造,析构, 构造析构调用虚函数, 显式析构 #include using namespace std; class CPerson { const char* m_pName; public: CPerson(const char* pName) { /// 构造调用虚函数, 执行的本类...

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 312
精华内容 124
关键字:

虚函数在cpp中