关于C++虚函数,纯虚函数以及模板等重要概念的深入讨论(二)
2016-12-04 00:00
381 查看
摘要: 摘要: C++中核心功能的一些深入认识,理清虚函数、纯虚函数、析构与虚析构函数,模板函数与模板类之间的关系;并探讨如何在软件开发的过程中的合理的利用这些结构,从而实现高内聚,低耦合的思想,并使软件具备更好的扩展性和可靠性。
2.析构与虚析构函数
为了说明基类的析构函数必须为虚析构函数,我们来实践一下:在A的析构函数中加入输出cout << "This is A class." << endl;同理在B的析构函数中也加入输出cout << "This is B class." << endl;
最后在main函数objectC->print();下方加入语句:delete objectC; objectC = NULL;从而销毁对象,调用析构函数。如果基类A的析构函数非虚析构的话,运行结果如下:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202004/13/5f9120d9842a28a015ba838c86a8e316.png)
如果将基类A的析构函数改写为虚析构函数:virtual ~A();那么运行的结果如下:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202004/13/dae35afdae4d6d70943ded92cc8f87aa.png)
可以清晰的看到,在基类A中如果是非虚析构函数时,销毁objectC 对象的时候则没有调用B析构函数,而若为虚析构函数的话,就会调用B的析构函数。因此为了防止释放指向子类的基类指针时,子类发生内存泄露现象,我们必须将基类的析构函数设置为虚析构!
3.虚函数与纯虚函数
虚函数即是在声明函数的时候在前面加入virtual 关键字如:virtual void print(); 而纯虚函数则是这样定义的:virtual void print() = 0; 即纯虚函数没有实体,实体是需要它的继承重写来实现的。我们来看一段实例代码:
在上述的代码中我们新加入了一个类C,它里面包含了一个虚函数draw1,以及一个纯虚函数draw2;然后我们让B继承这个类,并且在B类中我们重写了draw2函数,如果不重写那么会出现以下错误:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202004/13/6e66b3d8c5ad1b8a061ba057fe5cdb53.png)
编译器告诉我们必须要重写draw2函数,这样程序就能顺利的运行了;我们把带有虚函数的类称为抽象类,即上述实例中C就为抽象类,抽象类的特点是:它没有实体,我们不能把抽象类给实例化,即不能定义一个抽象类的对象;感兴趣的同学可以试一下,编译器会报错的不能实例化抽象类。
既然抽象类不能被实例化,而且他的纯虚成员函数还必须被继承它的子类继承,那么这种结构有什么用呢?答案是,它可以实现很好的扩展,在大型软件的编写过程中抽象类和纯虚函数会经常的用到,如果你看设计模式的话,可以看到有很多的设计模式中会用到抽象类和纯虚函数,它可以实现一种接口的作用,其实如果抽象类中只有纯虚函数这一种结构,那么它跟C#以及java等语言中的接口(也有人叫协议)的概念是一样的,最新式的用于Iphone开发的Swift语言就大量的使用接口,所以人们习惯叫这种新式的语言为面向协议的语言。可见抽象类和纯虚函数是有多么的强大。建议大家如何对它们感兴趣的话,一定要看看设计模式,你会有很大的收获!
<未完待续>
2.析构与虚析构函数
为了说明基类的析构函数必须为虚析构函数,我们来实践一下:在A的析构函数中加入输出cout << "This is A class." << endl;同理在B的析构函数中也加入输出cout << "This is B class." << endl;
最后在main函数objectC->print();下方加入语句:delete objectC; objectC = NULL;从而销毁对象,调用析构函数。如果基类A的析构函数非虚析构的话,运行结果如下:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202004/13/5f9120d9842a28a015ba838c86a8e316.png)
如果将基类A的析构函数改写为虚析构函数:virtual ~A();那么运行的结果如下:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202004/13/dae35afdae4d6d70943ded92cc8f87aa.png)
可以清晰的看到,在基类A中如果是非虚析构函数时,销毁objectC 对象的时候则没有调用B析构函数,而若为虚析构函数的话,就会调用B的析构函数。因此为了防止释放指向子类的基类指针时,子类发生内存泄露现象,我们必须将基类的析构函数设置为虚析构!
3.虚函数与纯虚函数
虚函数即是在声明函数的时候在前面加入virtual 关键字如:virtual void print(); 而纯虚函数则是这样定义的:virtual void print() = 0; 即纯虚函数没有实体,实体是需要它的继承重写来实现的。我们来看一段实例代码:
// Test1.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "iostream" using namespace std; class C { virtual void draw1(){}; virtual void draw2() = 0; }; class A { private: int valueA; public: A(); A(int value); virtual ~A(); virtual void print(int value); }; //The class A realize. A::A() { valueA = 0; } A::A(int value) { valueA = value; } A::~A() { cout << "This is A class." << endl; } void A::print(int value) { cout << "This is A print and Value is :" << value <<endl; } class B:public A, public C { private: int valueB; public: B(); B(int value); ~B(); void print(int value); void draw2(); }; //The class B realize. B::B() { valueB = 0; } B::B(int value):A(value) { valueB = value; } B::~B() { cout << "This is B class." << endl; } void B::print(int value) { cout << "This is B print and Value is :" << value << endl; } void B::draw2() { cout << "This is B draw and Value is :" << valueB << endl; } int main(void) { A *objectA = new A(10); B *objectB = new B(20); A *objectC = objectB; objectA->print(1); objectB->print(2); objectC->print(3); delete objectC; objectC = NULL; return 0; }
在上述的代码中我们新加入了一个类C,它里面包含了一个虚函数draw1,以及一个纯虚函数draw2;然后我们让B继承这个类,并且在B类中我们重写了draw2函数,如果不重写那么会出现以下错误:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202004/13/6e66b3d8c5ad1b8a061ba057fe5cdb53.png)
编译器告诉我们必须要重写draw2函数,这样程序就能顺利的运行了;我们把带有虚函数的类称为抽象类,即上述实例中C就为抽象类,抽象类的特点是:它没有实体,我们不能把抽象类给实例化,即不能定义一个抽象类的对象;感兴趣的同学可以试一下,编译器会报错的不能实例化抽象类。
既然抽象类不能被实例化,而且他的纯虚成员函数还必须被继承它的子类继承,那么这种结构有什么用呢?答案是,它可以实现很好的扩展,在大型软件的编写过程中抽象类和纯虚函数会经常的用到,如果你看设计模式的话,可以看到有很多的设计模式中会用到抽象类和纯虚函数,它可以实现一种接口的作用,其实如果抽象类中只有纯虚函数这一种结构,那么它跟C#以及java等语言中的接口(也有人叫协议)的概念是一样的,最新式的用于Iphone开发的Swift语言就大量的使用接口,所以人们习惯叫这种新式的语言为面向协议的语言。可见抽象类和纯虚函数是有多么的强大。建议大家如何对它们感兴趣的话,一定要看看设计模式,你会有很大的收获!
<未完待续>
相关文章推荐
- 关于C++虚函数,纯虚函数以及模板等重要概念的深入讨论(三)
- C++信号处理
- C++继承与派生学习笔记
- C语言——内存分配的方式
- 益智C语言编程
- c语言堆排序解析
- <C++>_C++的枚举
- C++中整型随机数发生器的写法
- C语言笔记(4)
- <C++>_C++的类型检查更严格
- C语言实现顺序表的初始化,插入,删除,查找
- C/C++基础面试-Const的全面理解(C部分)
- 有关字符串的几个函数(自己编写的)
- C++ 的简单输出输入 HDU 1089~1096
- C++第11周mooc在线测评—第11周 类的继承
- C语言编程练习--念数字
- vimrc
- 贪心算法学习总结
- 在C语言中,double、long、unsigned、int、char类型数据所占字节数
- c语言常见错误处理方法