• 【C++基础之十一】虚函数的用法


    虚函数的作用和意义,就不进行说明了,这里主要讨论下虚函数的用法。


    1.典型的虚函数用法

    可以看到,只有标识为virtual的函数才会产生多态的效果,而且是编译多态。它只能借助指针或者引用来达到多态的效果。

    class A
    {
    public:
    	virtual void f(){cout<<"A::f()";}//虚函数
    	void g(){cout<<"A::g()";}//普通函数
    };
    
    class B :public A{
    public:
    	virtual void f(){cout<<"B::f()";}
    	void g(){cout<<"B::g()";}
    };
    
    class C :public A{
    public:
    	virtual void f(){cout<<"C::f()";}
    	void g(){cout<<"C::g()";}
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	A* pa=new B;//pa是指针喔
    	pa->f(); // 调用B::f()
    	pa->g(); // 调用A::g()
    	delete pa;
    
    	pa=new C;
    	pa->f(); // 调用C::f()
    	pa->g(); // 调用A::g()
    	delete pa;
    
    	pa=NULL;
    	return 0;
    }


    2.虚函数的默认继承

    虚函数是默认继承virtual属性的,即使在子类中没有标识virtual。

    class A
    {
    public:
    	virtual void f(){cout<<"A::f()";}
    };
    
    class B :public A{
    public:
    	void f(){cout<<"B::f()";}//不加virtual了
    };
    
    class C :public B{
    public:
    	void f(){cout<<"C::f()";}//也不加virtual了
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	A* pa=new B;
    	pa->f(); // 调用B:f()
    	delete pa;
    
    	pa=new C;
    	pa->f(); // 调用C:f()
    	delete pa;
    
    	pa=NULL;
    	return 0;
    }


    3.纯虚函数

    纯虚函数和Java中的接口很像了,因为纯虚函数的存在导致了该类成了抽象类,它的主要作用就是规范接口,把实现留给子类。如果子类没有实现它的所有虚函数,那么该子类也是一个抽象类,通用不能进行实例化。

    class A
    {
    public:
    	virtual void f()=0;//纯虚函数,导致该类为抽象类
    };
    
    class B :public A{
    public:
    	virtual void f(){cout<<"B::f()";}
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	//A* pa=new A;//出错,不能实例化抽象类
    	A* pa=new B;
    	pa->f();//调用B::f()
    	delete pa;
    
    	pa=NULL;
    	return 0;
    }


    4.虚函数的调用模型

    子类调用父类函数只有虚函数才得以执行,普通函数只会调用父类函数,不过要注意以下的h()可不能是构造函数或者析构函数,不然多态就无法实现。

    class A
    {
    private:
    	virtual void f(){cout<<"A::f()"<<endl;}
    	void g(){cout<<"A::g()"<<endl;}
    public:
    	void h(){f();g();}
    };
    
    class B :public A{
    private:
    	virtual void f(){cout<<"B::f()"<<endl;}
    	void g(){cout<<"B::g()"<<endl;}
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	B b;
    	b.h();//调用父类的h(),分别再调用f()和g()。f()为虚函数调用子类B::f(),g()为普通函数调用父类A::g()。
    
    	return 0;
    }

    5.虚析构函数

    虚构函数可以是虚函数,甚至是纯虚函数。如果它作为一个基类,那析构函数必须是虚函数。

    而构造函数不能是虚函数。

    class A
    {
    public:
        A(){p_a=new char[1];cout<<"new 1"<<endl;}
    	virtual ~A(){delete[] p_a;cout<<"delete 1"<<endl;}//正常
    	//~A(){delete[] p_a;cout<<"delete 1"<<endl;}//异常,内存泄漏,~B()并没有被执行到
    private:
    	char* p_a;
    };
    
    class B :public A{
    public:
    	B(){p_b=new char[2];cout<<"new 2"<<endl;}
    	~B(){delete[] p_b;cout<<"delete 2"<<endl;}//能不能正确执行~B()成了关键
    private:
    	char* p_b;
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	A* pa=new B;
    	delete pa;
    
    	return 0;
    }


  • 相关阅读:
    iOS优化内存方法推荐
    Swift和OC,是编译型语言、解释性语言、运行时语言
    redis常用命令
    redis 基本类型
    spring中事务配置
    redis 基本概览
    ThreadLocal 类说明
    spring 中 AOP 功能
    ps抠图简单方法
    nginx配置文件中location说明
  • 原文地址:https://www.cnblogs.com/james1207/p/3333760.html
Copyright © 2020-2023  润新知