1. 概念
抽象类的定义:函数前面为 vritual 并且函数体为 “=0” 的函数称为纯虚函数。含纯虚函数的类称为抽象类。
抽象类的作用:向下(给派生类)定义好框架,向上(应用程序)提供统一的接口。
抽象类要注意的点:
1)抽象类不能够用来实例化对象。例如:实例化一个人时可以是"英国人",“中国人”,而不是"人类"。
2)如果派生类没有实现完父类所有的纯虚函数,那么派生类依然是抽象类,要么将剩下的纯虚函数实现,要么进一步派生子类在子类中实现。
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
class Human {
private:
int a;
public:
virtual void eating(void) = 0;
virtual void wearing(void) = 0;
virtual void driving(void) = 0;
virtual ~Human() { cout<<"~Human()"<<endl; }
};
class Englishman : public Human {
public:
void eating(void) { cout<<"use knife to eat"<<endl; }
void wearing(void) {cout<<"wear english style"<<endl; }
void driving(void) {cout<<"drive english car"<<endl; }
virtual ~Englishman() { cout<<"~Englishman()"<<endl; }
};
class Chinese : public Human {
public:
void eating(void) { cout<<"use chopsticks to eat"<<endl; }
void wearing(void) {cout<<"wear chinese style"<<endl; }
//void driving(void) {cout<<"drive chinese car"<<endl; }
virtual ~Chinese() { cout<<"~Chinese()"<<endl; }
};
class Guangximan : public Chinese {
void driving(void) {cout<<"drive guangxi car"<<endl; }
};
int main(int argc, char **argv)
{
//Human h;
Englishman e;
Guangximan g;
return 0;
}
2. 实战
02th:规范化组织和书写cpp代码的规则:
- h文件中定义类,cpp文件包含h文件,并实现类方法;
- 使用#ifdef 宏避免头文件被重复包含。
03th:抽象出共有属性放到基类中,子类继承基类,减少重复代码;
04th:基类引入虚函数实现多态–相同调用方法会根据不同对象调用对象所属类里面的函数。
05th:基类引入纯虚函数实现抽象类;好处是:
- 1)基类节省不必要的代码(往往并不需要基类实现虚函数的内容,只需要提供接口即可);
- 2)阻值生成基类的实例化对象
06th:编程工程化分工协作
将由一个人进行的工作拆分为分工协作:
- 1)应用编程:使用类;
- 2)类编程:提供类,比如Englishman, Chinese
第一步:修改Makefile,将类和应用程序分开。这样类更新(类的cpp文件)后不需要重新编译生成应用程序。
Human: main.o Chinese.o Englishman.o Human.o
g++ -o $@ $^
%.o : %.cpp
g++ -c -o $@ $<
改为:
Human: main.o libHuman.so
# -L./ 指定编译时动态库的路径,-l 指定链接的动态库的名字(libXXX.so中的XXX)
g++ -o $@ $< -L./ -lHuman
%.o : %.cpp
# -fPIC:编译选项 -- 编译为位置无关码
g++ -fPIC -c -o $@ $<
libHuman.so : Englishman.o Chinese.o Human.o
# -shared:连接选项 -- 链接为动态库
g++ -shared -o $@ $^
执行时用 LD_LIBRARY_PATH 指定链接路径:
LD_LIBRARY_PATH=<dir> ./Human
07th:抽象类界面的引入
06th的代码存在的问题:由于应用程序包含了类的头文件,如果类的头文件有修改,那么应用程序需要重新编译。
解决办法:应用程序应尽量包含内容比较固定的头文件,而不要去包含可能会经常变化的头文件。这就是抽象类界面机制。
app
---------------------------------
# 相对固定的接口(声明)
Human.h
---------------------------------
Englishman Chinese
08th:抽象类界面的实现
#应用编程:包含固定的引用接口头文件 Human.h,调用接口
app
---------------------------------
# 相对固定的接口(声明)
Human.h
---------------------------------
#类编程:包含固定的接口头文件 Human.h,实现方法
Englishman Chinese
这样,类编程就完全和应用独立开了。
09th:完善:基类和子类的析构函数都实现为虚函数,以在delete对象时实现多态。
注意,基类析构函数不能为纯虚函数,这样子类就要实现与基类同名的析构函数,这很怪异。