一、抽象类学习笔记
1.virtual修饰函数(虚函数)后面加=0就称为一个纯虚函数,一个类中只要有纯虚函数那么它就是一个抽象类。抽象类不能用来实例化对象,是用来给他的派生类定义好这些框架的,给使用这个类的程序定义好接口。
2.抽象类中可以部分是纯虚函数,部分是实现好的函数。
3.若派生类没有全部实现父类的存纯虚函数,由于继承关系,子类中也会有纯虚函数,因此子类也是抽象类,不能实例化对象。
4.多态中的两个特例在纯虚函数中是不成立的。(各自返回本对象的指针或引用、析构函数前加virtual)
5.实现为抽象类的好处:编写简单,可以防止适用此类来实例化对象。
6.抽象类界面
一个程序由多人合作编写,类编程和应用编程,目的是修改类重新生成库,但是应用程序不需要重新编译。
类编程:提供的类生成动态库
应用编程:使用动态库实现逻辑
例子中应用程序包含各个库的头文件,修改头文件就不行了,运行后程序崩溃了。
实现应用程序不包含类的头文件:
app
-------------------------------------
Human.h
-------------------------------------
Englishman Chineseman
使用这项技术把容易变化的类和应用程序隔离开了,中间引入一个相对固定的Human.h,它是一个接口是抽象类的界面。应用编程和类编程区分开来,互不影响。
7.析构函数可以定义为虚函数以达到在父类指针或引用在消除时调用子类的析构函数(然后再调用父类的析构函数)。但是析构函数不能定义为纯虚函数,因为纯虚函数就是没有实现,在链接期会报错(但是不是像普通函数一样报抽象类不能实例化对象)。
二、Demo
1.抽象类界面例子
/*main.cpp*/ #include "libhuman.h" int main() { Human *pe = new_english_man(); pe->eating(); pe->wearing(); delete_english_man(pe); return 0; }
/* libhuman.h */ #ifndef _LIBHUMAN_H__ #define _LIBHUMAN_H__ #include <iostream> using namespace std; class Human { int a; public: int b; virtual void eating() = 0; virtual void wearing() = 0; virtual ~Human() { //shouldn't be pure virtual function cout << "~Human()" << endl; } }; Human * new_english_man(); void delete_english_man(Human * ph); #endif
/* English.h */ #ifndef _ENGLISH_H__ #define _ENGLISH_H__ #include <iostream> #include "libhuman.h" using namespace std; class English : public Human { int a[10]; //new add to test public: void eating(); void wearing(); ~English(); }; #endif
/* English.cpp */ #include "English.h" void English::eating() { cout << "English::eating" << endl; } void English::wearing() { cout << "English::wearing" << endl; } English::~English() { cout << "English::~English" << endl; } Human * new_english_man() { return new English(); } void delete_english_man(Human * ph) { delete static_cast<English*>(ph); }
/* Makefile */ main : libHuman.so main.cpp g++ $^ -o $@ -L ./ -lHuman libHuman.so : English.cpp g++ -shared -fPIC -o $@ English.cpp clean: rm -rf libHuman.so *.o main # export LD_LIBRARY_PATH=./ ./main