zoukankan      html  css  js  c++  java
  • c++学习之多态(虚函数和纯虚函数)

            c++是面向对象语言,面向对象有个重要特点,就是继承和多态。继承之前学过了,就是一种重用类的设计方式。原有的类叫父类,或者基类,继承父类的类叫子类。在设计模式中,我们总是要避免继承,推荐用组合。因为继承会导致类爆炸。类太多了,就太累了。。。哈哈。。。

            说说多态,多态,从我们语言的语法上说,就是通过父类的指针能直接调用子类的方法,在父类的层面,无需了解子类的实现。在我理解来看,其实多态,也是解耦的一种实现方式,因为子类的实现和父类没有关系了,父类总是可以调用到相关的函数。

            但是如果我们父类有完整的一个实现,子类也有完整的实现,肿么办?父类肯定会调用自己的实现方法呀,一会我会讲解这个例子的。为了实现多态,c++语言引用了虚函数的概念。就是说,如果父类的某个函数是虚函数,那么好办,尽管你父类实现了这个虚函数也没关系,我通过指针调用的时候,我也会直接去找子类的相关实现,从而达到多态的效果。这个虚函数就有点像java里面的抽象方法了。但是留意细节哦....c++的虚函数,在父类也是可以实现的。我们来看一个完整的例子。

            1 创建一个BaseClass.h的头文件,对父类BaseClass进行声明。

    class BaseClass
    {
    protected:
    	int x;
    	int y;
    public:
    	BaseClass();
    	BaseClass(int a,int b);
    	void area();
    };


            2 创建一个BaseClazz.cpp源文件,对父类BaseClass进行实现。

    #include <iostream>
    #include <string>
    #include "BaseClass.h"
    using namespace std;
    
    BaseClass::BaseClass()
    {
    	x = 1;
    	y = 2;
    }
    BaseClass::BaseClass(int a,int b)
    {
    	x = a;
    	y = b;
    }
    void BaseClass::area()
    {
    	cout << "baseclass.area() call...." << endl;
    cout << x*y <<endl;
    }
    


            3 创建一个DeriveClass1.h的头文件,对子类DeriveClass1进行声明。

    #include "BaseClass.h"
    class DeriveClass1:public BaseClass
    {
    private:
    	int z;
    public:
    	void area();
    	void setValue(int a);
    	DeriveClass1();
    };


            4 创建一个DeriveClass1.cpp源文件,对子类进行实现。

    #include <iostream>
    #include "DeriveClass1.h"
    
    using namespace std;
    
    void DeriveClass1::area()
    {
    	cout << "DeriveClass1.area() call...." << endl;
    cout << x*y*z << endl;
    }
    
    void DeriveClass1::setValue(int a)
    {
    	z = a;
    }
    
    DeriveClass1::DeriveClass1()
    {
    	z = 3;
    }
    


            看到没有,父类子类都有一个area()函数,父类有两个成员变量x,y,子类有三个x,y,z。

            5 创建一个Main.cpp源文件,对以上的代码进行测试。

    #include <iostream>
    #include "DeriveClass1.h"
    using namespace std;
    
    int main()
    {
    
    	BaseClass *dc = new DeriveClass1();
    	dc->area();
    	return 1;
    }


            6 好了,这个时候,由于父类和子类都对area函数进行了实现,通过父类的指针来调用area函数,想都不用想,调用的是父类的area函数,尽管将子类的地址赋值给了父类的指针。看结果。

                    


            7 这样一来,多态的效果达不到了么,为了达到多态,肿么办?我们将BaseClass.h头文件中的area函数声明为virtual即可,其他地方均不变。看代码,

    class BaseClass
    {
    protected:
    	int x;
    	int y;
    public:
    	BaseClass();
    	BaseClass(int a,int b);
    	virtual void area();
    };


            8 这样一来,我们再次运行第六步的测试代码,截图如下:

                    

            这就是父类定义了虚函数的结果,尽管父类实现了该虚函数,但是父类的指针在指向子类的情况下,还是会调用子类对应的函数。

            9 这个时候又出现一种情况,如果父类真的是没必要实现这个area函数肿么办??如果你就这样直接不实现,在连接的时候会报错,哈哈。BaseClass.cpp代码如下:

    #include <iostream>
    #include <string>
    #include "BaseClass.h"
    using namespace std;
    
    BaseClass::BaseClass()
    {
    	x = 1;
    	y = 2;
    }
    BaseClass::BaseClass(int a,int b)
    {
    	x = a;
    	y = b;
    }
    void BaseClass::area();


            连接时报错如下:

    --------------------Configuration: DeriveDemo - Win32 Debug--------------------
    Compiling...
    BaseClazz.cpp
    Skipping... (no relevant changes detected)
    DeriveClass1.cpp
    Linking...
    BaseClazz.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall BaseClass::area(void)" (?area@BaseClass@@UAEXXZ)
    Debug/DeriveDemo.exe : fatal error LNK1120: 1 unresolved externals
    执行 link.exe 时出错.
    
    DeriveDemo.exe - 1 error(s), 0 warning(s)
    


            10 这个时候,纯虚函数就派上用场了,我们只需要将虚函数的定义后面赋值为0,即可。看看BaseClass.h头文件的定义。

    class BaseClass
    {
    protected:
    	int x;
    	int y;
    public:
    	BaseClass();
    	BaseClass(int a,int b);
    	virtual void area()=0;
    };


            11 然后编译链接执行。。执行结果如下:



            12 纯虚函数和虚函数有什么区别,我们通过上面的定义可以看出:

                    虚函数定义:virtvual void area();

                    纯虚函数的定义:virtual void area()=0;

                    虚函数,在父类中是必须实现的。

                    纯虚函数,在父类中是可以不用实现的。

              熟悉java的同学发现这个有没有一点想抽象类和接口呀。哈哈。。






  • 相关阅读:
    使用 Promise.all 同时发起多个请求
    vite 开发 Cesium 程序最佳配置实践
    【linux学习】使用grep命令获取过滤的数据作为下个命令的入参
    记一次k8s depolyment失败处理
    powerdesigner导出excel数据字典
    vue 时间格式
    ASP.NET MVC4 跨域配置
    Win10系统中切换虚拟桌面的快捷键如何设置
    不顾一切最简NHinbernate配置并读写数据库
    Windows time_wait过多解决办法
  • 原文地址:https://www.cnblogs.com/pangblog/p/3243874.html
Copyright © 2011-2022 走看看