抽象类,虚函数,纯虚函数的意义

  C语言是面向过程的语言,C++是面向对象的语言,区分它们面向什么的重要区别在于C++比C多个类。那么在我看来,抽象就是类的升华。

  一般刚学习C++的时候,抽象这个东西给人最大的感觉就是太抽象,很难理解。心里总是想着,其实这样或那样就能解决这个问题了,为什么要学这个?增加一个抽象类还增加一段代码,费事不说还不容易理解,所以当时我对抽象还是很抗拒的。但是当工作中真正用到这个的时候,就觉得这个东西真是太好了,任何其它的方案都无法代替抽象。

  为什么这样说呢?首先C++是强类型语言,对于一个数组或链表来讲,它们都只能是一种类型。它不像Python那种弱类型语言,一个列表里想放什么类型就放什么类型。

  假如我有一个小农场,农场里有5只鸡,3只鸭,2头牛,4头猪,1只狗。我希望表示出每一只动物的当天的生理状况和饮食起居。

 1 #include "stdafx.h"
 2 #include <iostream>
 3 #include <list>
 4 using namespace std;
 5
 6 //每个小动物都有吃饭这个动作,Eat()这个函数判断当前是否是饭点,如果是的话就吃饭
 7 class Chook
 8 {
 9 public:
10     void Eat() {}
11 };
12 class Duck
13 {
14 public:
15     void Eat() {}
16 };
17 class Pig
18 {
19 public:
20     void Eat() {}
21 };
22 class Cow
23 {
24 public:
25     void Eat() {}
26 };
27 class Dog
28 {
29 public:
30     void Eat() {}
31 };
32
33
34 int main()
35 {
36     list<Chook> chookList;
37     list<Duck> duckList;
38     list<Pig> pigList;
39     list<Cow> cowList;
40     list<Dog> dogList;
41
42     /*
43     Chook chook;
44     chookList.push_back(chook);
45     ……
46     将每一种小动物添加到对应的链表中
47     */
48
49     while (1)
50     {
51         for (auto p = chookList.begin();p != chookList.end();p++)
52         {
53             p->Eat();
54         }
55         for (auto p = duckList.begin();p != duckList.end();p++)
56         {
57             p->Eat();
58         }
59         for (auto p = pigList.begin();p != pigList.end();p++)
60         {
61             p->Eat();
62         }
63         for (auto p = cowList.begin();p != cowList.end();p++)
64         {
65             p->Eat();
66         }
67         for (auto p = dogList.begin();p != dogList.end();p++)
68         {
69             p->Eat();
70         }
71     }
72
73     return 0;
74 }

  在这个循环中,每一个链表都得遍历一次,并调用当前小动物的Eat()函数,麻烦不说,还容易出错。在这个例子中,无论是什么动物,他们的本质都是动物,他们都有吃喝拉撒睡的动作,C++给我们提供了一个抽象的功能,可以把这些具体动物的类抽象成一个概括这些动物的父类。

  以下为知识点:

  在C++中,如果一个类中包含纯虚函数的话,那么这个类就是抽象类。纯虚函数用下面的方法来表示。

1 class A
2 {
3 public:
4     virtual void Fun(int a, double b) = 0;
5 };

  成员函数Fun的返回值和参数都是任意的,需要用virtual来修饰变成虚函数,最后加上“=0”变成了纯虚函数。纯虚函数不能实现具体功能,只能由继承它的子类来实现。抽象类不能实例化对象,也就是说下面的写法是错误的。

1     A a;    //错!抽象类不能实例化对象

  如果子类A1想继承A,就跟正常的继承方法是一样的。有一点需要注意,如果A1没有全部实现A中的纯虚函数,那么A1也是抽象类,也不能实例化。所以如果想让A1能够实例化,那么就必须全部实现A中的纯虚函数。

  说完了纯虚函数,那么虚函数的作用是什么呢?虚函数就是现在父类中实现好了,如果子类能用的上就用,用不上自己重新实现一个就好了。

  了解了抽象,虚函数和纯虚函数的意义,我们看一下上边的农场应该怎么用这个方法来实现。

 1 #include "stdafx.h"
 2 #include <iostream>
 3 #include <list>
 4 using namespace std;
 5
 6 //每个小动物都有吃饭这个动作,Eat()这个函数判断当前是否是饭点,如果是的话就吃饭
 7 class Animal
 8 {
 9 public:
10     Animal();
11     virtual ~Animal() {}
12
13     virtual void Eat() = 0;
14     virtual void Drink() = 0;
15     virtual void Sleep()
16     {
17         //每天晚上睡
18     }
19
20 protected:
21     int weight; //体重
22
23 private:
24 };
25
26 class Chook :public Animal
27 {
28 public:
29     virtual void Eat() {}
30     virtual void Drink() {}
31 };
32 class Duck :public Animal
33 {
34 public:
35     virtual void Eat() {}
36     virtual void Drink() {}
37 };
38 class Pig :public Animal
39 {
40 public:
41     virtual void Eat() {}
42     virtual void Drink() {}
43     virtual void Sleep()
44     {
45         //吃完了就睡
46     }
47 };
48 class Cow :public Animal
49 {
50 public:
51     virtual void Eat() {}
52     virtual void Drink() {}
53 };
54 class Dog :public Animal
55 {
56 public:
57     virtual void Eat() {}
58     virtual void Drink() {}
59 };
60
61 int main()
62 {
63     list<Animal*> animalList;
64
65     for (int i = 0; i < 5; i++)
66     {
67         Animal* p = new Chook();
68         animalList.push_back(p);
69     }
70     /*
71     将每一种小动物添加到对应的链表中
72     */
73
74     while (1)
75     {
76         for (auto pNode = animalList.begin(); pNode != animalList.end(); pNode++)
77         {
78             (*pNode)->Eat();
79             (*pNode)->Drink();
80             (*pNode)->Sleep();
81         }
82     }
83
84     for ( auto pNode = animalList.begin(); pNode != animalList.end(); pNode++)
85     {
86         delete *pNode;
87     }
88
89     return 0;
90 }

  从第7行开始,我们定义了一个Animal的抽象类,因为每个动物吃的喝的都不一样,所以把Eat和Drink定义成了纯虚函数,等到它的子类去实现。但是睡觉的话,大多数动物应该都是晚上睡的,所以定义了一个虚函数Sleep,实现为晚上睡觉,只有猪那个类里重新定义了Sleep这个函数,因为猪是吃完了就睡。

  使用的时候也很简单,定义一个Animal*类型的链表(也可以定义为数组),可以装载不同小动物的指针,通过指针调用函数的时候,你的程序会自动的分辨出它属于哪个类,并调用了对应的函数。

  其实在这个简短的例子当中,并不能真切的感受到抽象的好处,因为这个例子给人最直观的感觉就是调用的代码没有少多少,抽象出来的父类却增加了一些麻烦。但是我使用C++这些年的感觉就是,C++没有一个特性是多余的。如果你一开始因为不了解这些特性而使用自己认为还可以的方法去实现一个功能,慢慢的你就会为这个做法浪费越来越多的时间去弥补。

  举个在工业控制软件中比较常见的例子。你的设备中有一个工业相机,你的软件就需要调用这个相机的API来使相机工作。但是你的领导突然有一天说,他发现另一款相机性能差不多,但是价格便宜许多,要换相机!如果你一直在你的主程序中直接调用原相机的API函数,那换相机对你来讲将是一个噩梦,改代码的面积大不说,还会增加不少的bug。使用抽象来解决这个问题就容易很多,可以单独为相机这个抽象类做一个接口,然后让它不同的子类具体去调用不同相机的API函数。而你主程序里所有关于相机的操作,都来调用这些个接口函数,这时问题迎刃而解!

原文地址:https://www.cnblogs.com/songliduo/p/9314579.html

时间: 2024-10-29 19:08:31

抽象类,虚函数,纯虚函数的意义的相关文章

C++ 虚函数&amp;纯虚函数&amp;抽象类&amp;接口&amp;虚基类(转)

http://www.cnblogs.com/fly1988happy/archive/2012/09/25/2701237.html 1. 多态 在面向对象语言中,接口的多种不同实现方式即为多态.多态是指,用父类的指针指向子类的实例(对象),然后通过父类的指针调用实际子类的成员函数. 多态性就是允许将子类类型的指针赋值给父类类型的指针,多态是通过虚函数实现的. 多态可以让父类的指针有“多种形态”,这是一种泛型技术.(所谓泛型技术,就是试图使用不变的代码来实现可变的算法). 2. 虚函数 2.1

虚函数/纯虚函数/抽象类/接口/虚基类

1.多态 在面向对象语言中,接口的多种不同实现方式即为多态.多态是指,用父类的指针指向子类的实例(对象),然后通过父类的指针调用实际子类的成员函数. 在Java中,没有指针,就直接用父类实例化子类对象 多态性就是允许将子类类型的指针赋值给父类类型的指针,多态是通过虚函数实现的,多态可以让父类的指针有“多种形态”,这是一种泛型技术. 所谓泛型技术,就是试图使用不变的代码来实现可变的算法 2.虚函数 在基类的类定义中,定义虚函数的一般形式: Virtual 函数返回值类型 虚函数名(形参表){ 函数

抽象类中定义纯虚函数

首先看一段代码: class Instrument { public: virtual void play()const=0//非法的定义在抽象类中定义纯虚函数 { cout<<"Instrument Play\n"; } }; class Wind:public Instrument { void play( )const { cout<<"Wind Play\n"; } }; void main() { Wind s; Instrumen

C++中的 虚函数 纯虚函数 虚基类(virtual)

前言:需要了解三者的区别,必须要掌握多态的三个必要条件: 继承 重载 父类指针指向子类对象. 虚函数 纯虚函数 虚基类三者区别 1.虚函数是用于多态中virtual修饰父类函数,确保父类指针调用子类对象时,运行子类函数的. 2.纯虚函数是用来定义接口的,也就是基类中定义一个纯虚函数,基类不用实现,让子类来实现. 3.虚基类是用来在多继承中,比如菱形继承中,如果两个父类继承自同一个类,就只实例化一个父类 ①虚函数第一个是没有使用多态(只用继承)的一般实现方式: class A { public:

【C/C++学院】0823-静态联合编译与动态联合编译/父类指针子类指针释放/虚函数/纯虚函数概念以及虚析构函数/抽象类与纯虚函数以及应用/虚函数原理/虚函数分层以及异质链表/类模板的概念以及应用

静态联合编译与动态联合编译 #include <iostream> #include <stdlib.h> //散列 void go(int num) { } void go(char *str) { } //class //::在一个类中 class A { public: void go(int num) { } void go(char *str) { } }; void main() { ///auto p = go;编译的阶段,静态联编 void(*p1)(char *s

C++ Primer 学习笔记_34_面向对象编程(5)--虚函数与多态(二):纯虚函数、抽象类、虚析构函数、动态创建对象

C++ Primer 学习笔记_34_面向对象编程(5)--虚函数与多态(二):纯虚函数.抽象类.虚析构函数.动态创建对象 一.纯虚函数 1.虚函数是实现多态性的前提 需要在基类中定义共同的接口 接口要定义为虚函数 2.如果基类的接口没办法实现怎么办? 如形状类Shape 解决方法 将这些接口定义为纯虚函数 3.在基类中不能给出有意义的虚函数定义,这时可以把它声明成纯虚函数,把它的定义留给派生类来做 4.定义纯虚函数: class <类名> { virtual <类型> <函

纯虚函数和抽象类

-------------------siwuxie095 纯虚函数 在 C++ 中,用 纯 字来修饰虚函数,即 纯虚函数 纯虚函数没有函数体,同时在定义时,函数名的后边要加 =0 看如下实例: 纯虚函数在虚函数表中的实现: 如果定义了一个 Shape 类,因为其中有虚函数和纯虚函数, 所以 Shape 类一定有一个虚函数表,当然,也就会有一个 虚函数表指针 在虚函数表中,如果是一个普通虚函数,则对应的函数指针 就是一个有意义的值,如果是一个纯虚函数,则对应的函数 指针的值就是 0 抽象类 纯虚

C++学习笔记(十二):类继承、虚函数、纯虚函数、抽象类和嵌套类

类继承 在C++类继承中,一个派生类可以从一个基类派生,也可以从多个基类派生. 从一个基类派生的继承称为单继承:从多个基类派生的继承称为多继承. 1 //单继承的定义 2 class B:public A 3 { 4 < 派生类新定义成员> 5 }; 6 //多继承的定义 7 class C:public A,private B 8 { 9 < 派生类新定义成员> 10 }; 我们这篇主要说单继承. 派生类共有三种C++类继承方式: 公有继承(public) 基类的公有成员和保护成

抽象类与纯虚函数

          一.啥是抽象类? 含有纯虚函数的类被称为抽象类.抽象类是一种特殊的类,它是为了抽象和设计的目的而建立的,它处于继承结构的上层.抽象类是不能定义对象的,在实际中为了强调一个类是抽象类,可将该类的构造函数说明为受保护的访问控制权限. 抽象类的主要作用就是描述一组相关子类的通用操作接口.一般而言,抽象类只描述这组子类共同的操作接口,而实现交给子类来完成. 抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出.如果派生类没有重新定义纯虚函数,而派生类只是继承基类的纯虚函数,则这个派

Hello,C++(5)纯虚函数和抽象类

纯虚函数和抽象类 下面通过一个例子来说明纯虚函数的定义方法 在这个类当中,我们定义了一个普通的虚函数,并且也定义了一个纯虚函数.那么,纯虚函数是什么呢??从上面的定义可以看到,纯虚函数就是没有函数体,同时在定义的时候,其函数名后面要加上“= 0”. 纯虚函数的实现原理 本节从虚函数表的角度来说明纯虚函数的实现原理. 上面就是我们在前面课程讲到的多态的实现原理,在讲这一部分的时候,讲到了虚函数表以及虚函数表指针.如果我们定义了Shape这样的类,那么,Shape类当中,因为有虚函数和纯虚函数,所以