虚函数:
//什么是多态:指相同对象收到不同消息或不同对象收到相同消息时产生不同的动作
//静态多态(早绑定)/动态多态(晚绑定)
#include <iostream>
#include <string>
using namespace std;
class Rectt {
public:
int calcArea(int width);
int calcArea(int width, int heigth);
};
//什么是多态:指相同对象收到不同消息或不同对象收到相同消息时产生不同的动作
//静态多态(早绑定)/动态多态(晚绑定)
#include "Rectt.h"
int Rectt::calcArea(int width) {
cout << "Rectt_width : " << width << endl;
return 0;
}
int Rectt::calcArea(int width, int heigth) {
cout << "Rectt_calcArea : " << width * heigth << endl;
return 0;
}
#ifndef SHAPE_H //解决重定义
#define SHAPE_H
#include <iostream>
#include <string>
using namespace std;
class Shape {
public:
Shape();
~Shape();
// double clacArea();//与子类Circle和Rect完全相同的函数
virtual double clacArea();
};
#endif
#include "Shape.h"
Shape::Shape() {
cout << "Shape()" << endl;
}
Shape::~Shape() {
cout << "~Shape()" << endl;
}
double Shape::clacArea() {
cout << "Shape_clacArea" << endl;
return 0;
}
#ifndef RECT_H //解决重定义
#define RECT_H
#include "Shape.h"
class Rect: public Shape {
public:
Rect(int width, int height);
~Rect();
// double clacArea();//与父类Shape完全相同的函数
virtual double clacArea();
private:
double mWidth;
double mHeight;
};
#endif
#include "Rect.h"
Rect::Rect(int width, int height) {
mWidth = width;
mHeight = height;
cout << "Rect()" << endl;
}
Rect::~Rect() {
cout << "~Rect()" << endl;
}
double Rect::clacArea() {
cout << "Rect_clacArea()" << endl;
return mWidth * mHeight;
}
#ifndef CIRCLE_H //解决重定义
#define CIRCLE_H
#include "Shape.h"
class Circle: public Shape {
private:
double m_dR;
public:
Circle(int r);
~Circle();
// double clacArea();//与父类Shape完全相同的函数
virtual double clacArea();
};
#endif
#include "Circle.h"
Circle::Circle(int r) {
m_dR = r;
cout << "Circle()" << endl;
}
Circle::~Circle() {
cout << "~Circle()" << endl;
}
double Circle::clacArea() {
cout << "Circle_clacArea" << endl;
return 3.14 * m_dR * m_dR;
}
#include "Shape.h"
#include "Circle.h"
#include "Rect.h"
#include "Rectt.h"
/**
* virtual虚函数的使用限制:
*/
// 一、
//virtual int getAge(){ // 普通函数不能是虚函数
// cout << "虚析构函数" << endl;
//}
// 二、
//class Animal{
//public:
// virtual static int getCount(); //静态成员函数不能是虚函数
//};
// 三、
//class Animal {
//public:
// inline virtual int getCount(); //内联函数不能是虚函数
//};
// 四、
//class Animal {
//public:
// virtual Animal(); //构造函数不能是虚函数
//};
/**
* 什么是多态:指的是相同对象收到不同消息或不同对象收到相同消息时产生不同的动作
*
* 静态多态(早绑定)/动态多态(晚绑定)
*/
int main() {
// 静态多态的使用(早绑定):编译器在编译之前可以确定要调用的是哪个函数
Rectt rectt;
rectt.calcArea(10);
rectt.calcArea(10, 20);
// 动态多态的使用(晚绑定):编译器在编译之前可以不能确定要调用的是哪个函数
// 与java强制类型转换相同,在继承篇之强制类型转换isA的关系有提及
// 若要解决或者消除这种与java强制类型转换相同的效果,C++给出虚函数方案,关键字virtual
// 在父类添加关键字virtual的函数,则调用的是子类的该函数而不是父类的
Shape *s1 = new Circle(3);
Shape *s2 = new Rect(3, 6);
s1->clacArea(); // 父类的clacArea()不添加virtual关键字,则调用的是父类Shape的clacArea()
s2->clacArea(); // 父类的clacArea()不添加virtual关键字,则调用的是父类Shape的clacArea()
// virtual关键字也会继承,即如果父类的clacArea()添加了virtual关键字,
// 则子类Circle和Rect的的clacArea()前面就算不加virtual关键字,系统默认也是加上的,我们推荐手动添加
// 上面的也就是所谓的"函数覆盖(重写)"概念
/**
* 如果是实例化子类对象,则概念是"隐藏"
*/
// Circle *c1 = new Circle(3.0);
// c1->Shape::clacArea();// 调用的是父类Shape的clacArea()
// c1->clacArea();// 调用的是自身的clacArea()
delete s1;
s1 = NULL;
delete s2;
s2 = NULL;
return 0;
}
虚析构函数:
#ifndef SHAPE_H //解决重定义
#define SHAPE_H
#include <iostream>
#include <string>
using namespace std;
class Shape {
public:
Shape();
// ~Shape();
virtual ~Shape();//虚析构函数,
//作用:确保定义Shape指针对象指向子类对象时候(Shape *s1 = new Circle(3);)
// delete s1时子类对象Circle也会回调析构函数
// double clacArea();//与子类Circle和Rect完全相同的函数
virtual double clacArea();
};
#endif
#include "Shape.h"
Shape::Shape() {
cout << "Shape()" << endl;
}
Shape::~Shape() {
cout << "~Shape()" << endl;
}
double Shape::clacArea() {
cout << "Shape_clacArea" << endl;
return 0;
}
#ifndef RECT_H //解决重定义
#define RECT_H
#include "Shape.h"
class Rect: public Shape {
public:
Rect(int width, int height);
virtual~Rect();
// double clacArea();//与父类Shape完全相同的函数
virtual double clacArea();
private:
double mWidth;
double mHeight;
};
#endif
#include "Rect.h"
Rect::Rect(int width, int height) {
mWidth = width;
mHeight = height;
cout << "Rect()" << endl;
}
Rect::~Rect() {
cout << "~Rect()" << endl;
}
double Rect::clacArea() {
cout << "Rect_clacArea()" << endl;
return mWidth * mHeight;
}
#ifndef CIRCLE_H //解决重定义
#define CIRCLE_H
#include "Shape.h"
#include "Coordinate.h"
class Circle: public Shape {
private:
double m_dR;
public:
Circle(int r);
virtual~Circle();
// double clacArea();//与父类Shape完全相同的函数
virtual double clacArea();
protected:
double mR;
Coordinate *m_pCenter;
};
#endif
#include "Circle.h"
#include "Coordinate.h"
Circle::Circle(int r) {
m_dR = r;
m_pCenter = new Coordinate(3,5);
cout << "Circle()" << endl;
}
Circle::~Circle() {
delete m_pCenter;
m_pCenter = NULL;
cout << "~Circle()" << endl;
}
double Circle::clacArea() {
cout << "Circle_clacArea" << endl;
return 3.14 * m_dR * m_dR;
}
#ifndef COORDINATE_H //解决重定义
#define COORDINATE_H
#include <iostream>
using namespace std;
class Coordinate {
public:
Coordinate(int x, int y);
~Coordinate();
private:
int mX;
int mY;
};
#endif
#include "Coordinate.h"
Coordinate::Coordinate(int x, int y) :
mX(x), mY(y) {
cout << "Coordinate()" << endl;
}
Coordinate::~Coordinate() {
cout << "~Coordinate()" << endl;
}
#include <iostream>
#include <stdlib.h>
#include "Shape.h"
#include "Circle.h"
#include "Rect.h"
using namespace std;
/**
* virtual虚函数的使用限制:
*/
// 一、
//virtual int getAge(){ // 普通函数不能是虚函数
// cout << "虚析构函数" << endl;
//}
// 二、
//class Animal{
//public:
// virtual static int getCount(); //静态成员函数不能是虚函数
//};
// 三、
//class Animal {
//public:
// inline virtual int getCount(); //内联函数不能是虚函数
//};
// 四、
//class Animal {
//public:
// virtual Animal(); //构造函数不能是虚函数
//};
int main() {
Shape *s1 = new Circle(3);
Shape *s2 = new Rect(3, 6);
s1->clacArea(); // 父类的clacArea()不添加virtual关键字,则调用的是父类Shape的clacArea()
s2->clacArea(); // 父类的clacArea()不添加virtual关键字,则调用的是父类Shape的clacArea()
/**
* 如果是实例化子类对象,则概念是"隐藏"
*/
// Circle *c1 = new Circle(3.0);
// c1->Shape::clacArea();// 调用的是父类Shape的clacArea()
// c1->clacArea();// 调用的是自身的clacArea()
/**
* delete s1和delete s2若是Shape不是虚析构函数,则Circle和Rect不会回调析构函数,造成内存泄漏
*/
delete s1;
s1 = NULL;
delete s2;
s2 = NULL;
cout << "虚析构函数" << endl;
return 0;
}
虚函数表:
#ifndef SHAPE_H //解决重定义
#define SHAPE_H
#include <iostream>
#include <string>
using namespace std;
class Shape {
public:
Shape();
// ~Shape();
virtual ~Shape();//虚析构函数,
//作用:确保定义Shape指针对象指向子类对象时候(Shape *s1 = new Circle(3);)
// delete s1时子类对象Circle也会回调析构函数
// double clacArea();//与子类Circle和Rect完全相同的函数
// virtual double clacArea();
};
#endif
#include "Shape.h"
Shape::Shape() {
// cout << "Shape()" << endl;
}
Shape::~Shape() {
// cout << "~Shape()" << endl;
}
//double Shape::clacArea() {
// cout << "Shape_clacArea" << endl;
// return 0;
//}
#ifndef CIRCLE_H //解决重定义
#define CIRCLE_H
#include "Shape.h"
class Circle: public Shape {
public:
Circle(int r);
virtual~Circle();
// double clacArea();//与父类Shape完全相同的函数
// virtual double clacArea();
//protected:
int mR;
};
#endif
#include "Circle.h"
Circle::Circle(int r) {
mR = r;
// cout << "Circle()" << endl;
}
Circle::~Circle() {
// cout << "~Circle()" << endl;
}
//double Circle::clacArea() {
// cout << "Circle_clacArea" << endl;
// return 3.14 * m_dR * m_dR;
//}
#include <iostream>
using namespace std;
/**
* 函数:在内存中指的是一块二进制执行逻辑
*/
/**
* 虚函数与虚析构函数原理:
*
* 虚析构函数原理:父类执行虚析构函数时会先找到子类的虚函数表指针再找到子类的虚函数表的子类虚析构函数二进制执行入口位置执行<见下面虚函数的原理分析>
*
* 虚函数的原理:参见.png图片
* 首先如果类对象不存在虚函数,则类对象就没有虚函数表指针,若存在,则每个类对象都有自己的一个虚函数表指针成员属性和虚函数表(可以理解为虚函数的函数库)
* 虚函数表存储着每个虚函数(也即是存储着虚函数的入口访问位置),
* 这个虚函数表指针指向的是虚函数表的入口位置,每个类对象的虚函数表的入口位置都不一样
*
* 实例一:若父类对象存在虚函数A,子类对象不存在虚函数A,则子类对象和父类对象虚函数表所存储的虚函数A所指向的二进制函数入口访问位置相同,
* 参见Class_Circle_Shape.PNG和子类虚函数表结构一.PNG
*
* 实例二:若父类对象存在虚函数A,子类对象也存在虚函数A,则子类对象和父类对象虚函数表所存储的虚函数A所指向的二进制函数入口访问位置不相同,
* 参见Class_Circle_Shape.PNG和子类虚函数表结构二.PNG,也就是所谓的函数"覆盖(重写)"概念
*
*
*/
/**
* 1、函数"隐藏"概念详见C++继承篇之隐藏
* 2、函数"覆盖(重写)"概念见上面实例二,与Java多态篇相比存在一定的差异,与"隐藏"不同的是该函数多了virtual关键,即原来的函数变成了虚函数
*/
#include "Circle.h"
#include "Shape.h"
/**
* 概念说明:
* 1、对象大小:即是实例化对象时对象的成员属性所占据的内存大小
* 2、对象地址:
* 3、对象成员的地址:
* 4、虚函数表指针:
*/
int main() {
Shape shape;
cout << "Shape对象的大小 = "<< sizeof(shape) << endl;// 结果输出4,如果类对象不存在虚函数则输出1,默认系统为类对象分配1个单元
// 由于虚函数表指针也是一个指针,所以Shape就算没有成员属性,大小也是4,这个4就是虚函数表指针的大小
int *p = (int *)&shape;//强制类型
cout << "p的地址:"<< p << endl;
cout << "shape的地址:"<< &shape << endl;
cout << "shape第一个成员的地址即是虚函数表指针的地址:"<< (unsigned int)(*p) << endl;
Circle circle(100);
cout << "Circle对象的大小 = "<< sizeof(circle) << endl;// 结果输出24
int *c = (int *)&circle;//强制类型
cout << "c的地址:"<< c << endl;
cout << "circle的地址:"<< &circle << endl;
cout << "circle第一个成员的地址即是虚函数表指针的地址:"<< (unsigned int)(*c) << endl;
// cout << "circle第一个成员的地址即是虚函数表指针的地址:"<< (unsigned int)(*(++c)) << endl;
// cout << "circle第一个成员的地址即是虚函数表指针的地址:"<< (unsigned int)(*(c++)) << endl;
cout << "circle第一个成员的地址即是虚函数表指针的地址:"<< (*c) << endl;
// cout << "circle第一个成员的地址即是虚函数表指针的地址:"<< circle << endl;//这样子编译会出错
cout << "circle第二个成员的大小值:"<< circle.mR << endl;
cout << "circle第二个成员的地址即是mR的地址:"<< &(circle.mR) << endl;
cout << "虚函数表" << endl;
return 0;
}
纯虚函数:
#ifndef PERSON_H
#define PERSON_H
#include <iostream>
#include <string>
using namespace std;
class Person {
public:
// Person();//如果不加无参构造函数,则派生类要给基类有参构造函数的参数设置默认值
Person(string name);
virtual void work() = 0;//纯虚函数
virtual ~Person();// 虚函数
private:
string mName;
};
#endif
#include "Person.h"
//Person::Person() {
// cout << "Person()" << endl;
//}
Person::Person(string name) {
mName = name;
cout << "Person(string name)_name = " << name << endl;
}
Person::~Person() {
cout << "~Person()" << endl;
}
//void Person::work() {
// cout << "Person_play()" << "_name = " << mName << endl;
//}
//工人类
#ifndef WORKER_H
#define WORKER_H
#include "Person.h"
class Worker: public Person {
public:
Worker(string name, int age);
virtual ~Worker();
// virtual void work();//如果没有实现该虚函数,则Worker不能被实例化
private:
int mAge;
};
#endif
//工人类
#include "Worker.h"
Worker::Worker(string name, int age) :
Person(name) {
mAge = age;
cout << "Worker()" << endl;
}
Worker::~Worker() {
cout << "~Worker()" << endl;
}
//void Worker::work() {
// cout << "Worker::work()_mAge = " << mAge << endl;
//}
#ifndef DUSTMAN_H
#define DUSTMAN_H
#include "Worker.h"
class Dustman: public Worker {
public:
Dustman(string name, int age);
// virtual ~Dustman();
virtual void work();
};
#endif
//清洁工类
#include "Dustman.h"
//Dustman::Dustman(string name, int age) {
// cout << "Dustman()" << endl;
//}
Dustman::Dustman(string name, int age) :
Worker(name, age) {
}
//Dustman::~Dustman() {
// cout << "~Dustman()" << endl;
//}
void Dustman::work() {
cout << "Dustman::work()" << endl;
}
#include <iostream>
using namespace std;
#include "Dustman.h"
#include "Person.h"
#include "Worker.h"
/**
* 含有纯虚函数的类称为抽象类
*/
/**
* 纯虚函数类似于java的抽象函数,不同的是java的必须要由继承的子类去实现,而C++可以由最后要去实例化的子类去实现
*
* 有纯虚函数的抽象类不能直接实例化,这点与java相同
*/
int main() {
/*
* 因为创建派生类对象时要调用基类的构造函数,当基类没有定义构函数时就调用默认无参数的构造函数。
* 当只定义了有参的构造函数时就调用有参的构造函数,所以当派生类没有给基类传递参数时就会出现错误。
* 解决方法:可以在基类中重载一个无参构造函数,或者给有参构造函数的参数设置默认值。
*/
// Person p;
// Worker w("liugx", 27);
// w.work();
Dustman d("liugx", 27);
d.work();
cout << "C++纯虚函数" << endl;
return 0;
}
接口类:
#ifndef FLYABLE_H
#define FLYABLE_H
#include <iostream>
#include <string>
using namespace std;
/**
* 接口类
*/
class Flyable {
public:
virtual void tackoff() = 0;
virtual void land() = 0;
};
#endif
#include "Flyable.h"
//void Flyable::tackoff() {
// cout << "Flyable_tackoff()" << endl;
//}
//void Flyable::land() {
// cout << "Flyable_land()" << endl;
//}
#ifndef FIGHTERPLANE_H
#define FIGHTERPLANE_H
#include "Plane.h"
#include "Flyable.h"
class FighterPlane: public Plane,public Flyable{
public :
FighterPlane(){}
FighterPlane(string code);
virtual void tackoff();//实现父类的纯虚函数
virtual void land();//实现父类的纯虚函数
};
#endif
#include "FighterPlane.h"
FighterPlane::FighterPlane(string code): Plane(code) {
cout << "FighterPlane()" << endl;
}
void FighterPlane::tackoff() {
cout << "FighterPlane_tackoff()" << endl;
}
void FighterPlane::land() {
cout << "FighterPlane_land()" << endl;
}
#ifndef PLANE_H
#define PLANE_H
#include "Flyable.h"
//class Plane: public Flyable {
class Plane {
public:
Plane() {
}
Plane(string code);
// virtual void tackoff(); //实现父类的纯虚函数
// virtual void land(); //实现父类的纯虚函数
void printCode();
private:
string mCode;
};
#endif
#include "Plane.h"
Plane::Plane(string code) {
mCode = code;
cout << "Plane()" << endl;
}
//void Plane::tackoff() {
// cout << "Plane_tackoff()" << endl;
//}
//void Plane::land() {
// cout << "Plane_land()" << endl;
//}
void Plane::printCode() {
cout << "Plane::printCode()_code = " << mCode << endl;
}
#include "FighterPlane.h"
#include "Plane.h"
#include <iostream>
using namespace std;
/**
* 接口类:仅含有纯虚函数的类(无任何成员属性,只含有成员函数,并且所有成员函数都是纯虚函数--与java接口有些差异)
*
*
*可以使用接口类指针指向其子类对象,并调用子类对象中实现的接口类中纯虚函数。接口类中只能含纯虚函数,不能含数据成员
*
* 作用:接口类更多的是为了表达一种能力或者协议
*/
void flyMatch(Flyable *f1, Flyable *f2) {
f1->tackoff();
f1->land();
f2->tackoff();
f2->land();
}
void flyMatch_plane(Plane *f1, Plane *f2) {
f1->printCode();
f2->printCode();
}
int main() {
// Plane p1("001");
// Plane p2("002");
// p1.printCode();
// p2.printCode();
// flyMatch(&p1, &p2);
FighterPlane p0("000");
FighterPlane p3("003");
p0.printCode();
p3.printCode();
flyMatch(&p0, &p3);
flyMatch_plane(&p0, &p3);
// Flyable f;
cout << "C++接口类" << endl;
return 0;
}
运行时类型识别:与java泛型类似
#ifndef FLYABLE_H
#define FLYABLE_H
#include <iostream>
#include <string>
using namespace std;
/**
* 接口类
*/
class Flyable {
public:
virtual void tackoff() = 0;//纯虚函数
virtual void land() = 0;//纯虚函数
};
#endif
#include "Flyable.h"
//void Flyable::tackoff() {
// cout << "Flyable_tackoff()" << endl;
//}
//void Flyable::land() {
// cout << "Flyable_land()" << endl;
//}
#ifndef PLANE_H
#define PLANE_H
#include "Flyable.h"
class Plane: public Flyable {
//class Plane {
public:
Plane() {
}
Plane(string code);
virtual void tackoff(); //实现父类的纯虚函数
virtual void land(); //实现父类的纯虚函数
void carry();//运输
private:
string mCode;
};
#endif
#include "Plane.h"
Plane::Plane(string code) {
mCode = code;
cout << "Plane()" << endl;
}
void Plane::tackoff() {
cout << "Plane_tackoff()" << endl;
}
void Plane::land() {
cout << "Plane_land()" << endl;
}
void Plane::carry() {
cout << "Plane::carry()" << endl;
}
#ifndef BIRD_H
#define BIRD_H
#include "Flyable.h"
class Bird: public Flyable {
//class Bird {
public:
Bird() {
}
Bird(string code);
virtual void tackoff(); //实现父类的纯虚函数
virtual void land(); //实现父类的纯虚函数
void foraging();//觅食
private:
string mCode;
};
#endif
#include "Bird.h"
Bird::Bird(string code) {
mCode = code;
cout << "Bird(string code)" << endl;
}
void Bird::tackoff() {
cout << "Bird_tackoff()" << endl;
}
void Bird::land() {
cout << "Bird_land()" << endl;
}
void Bird::foraging() {
cout << "Bird_foraging()" << endl;
}
#include <iostream>
using namespace std;
#include <typeinfo>
#include "Flyable.h"
#include "Bird.h"
#include "Plane.h"
/**
* 运行时类型识别
*/
void doSomeThing(Flyable *obj) {
cout << typeid(*obj).name() << endl;
obj->tackoff();
if (typeid(*obj) == typeid(Bird)) {
Bird *bird = dynamic_cast<Bird *>(obj);
bird->foraging();
}
if (typeid(*obj) == typeid(Plane)) {
Plane *plane = dynamic_cast<Plane *>(obj);
plane->carry();
}
obj->land();
}
int main() {
// Bird b;
// doSomeThing(&b);
// Plane p;
// doSomeThing(&p);
// int i;
// cout << typeid(i).name() << endl;
// double d;
// cout << typeid(d).name() << endl;
Flyable *f = new Bird();
cout << typeid(f).name() << endl;
cout << typeid(*f).name() << endl;
cout << "C++ RTTI" << endl;
return 0;
}
异常处理:
#ifndef EXCEPTION_H
#define EXCEPTION_H
#include <iostream>
using namespace std;
class Exception {
public:
virtual ~Exception();
virtual void printException();
};
#endif
#include "Exception.h"
Exception::~Exception() {
cout << "~Exception()" << endl;
}
void Exception::printException() {
cout << "Exception::printException()" << endl;
}
#ifndef INDEXEXCEPTION_H
#define INDEXEXCEPTION_H
#include "Exception.h"
class IndexException : public Exception {
public:
// virtual ~IndexException();
virtual void printException();
};
#endif
#include "IndexException.h"
//void IndexException::~IndexException() {
// cout << "IndexException::~IndexException()" << endl;
//}
void IndexException::printException() {
cout << "IndexException::printException()" << endl;
}
#include <iostream>
using namespace std;
#include "Exception.h"
#include "IndexException.h"
void test() {
// throw 1;
// throw 0.1;
throw IndexException();
}
/**
* MinGW download addr http://sourceforge.net/projects/mingw/files/
*/
int main() {
/*try {
} catch (CFileException *e) {
} catch (CMemoryException *e) {
} catch (CException *e) {
}*/
try {
test();
} catch (int) {
cout << "异常int" << endl;
} catch (double &e) {
cout << "异常double :: " << e << endl;
} catch (Exception &e) {
e.printException();
} catch (IndexException &e) {
e.printException();
} catch (...) {
cout << "捕获所有的异常" << endl;
}
cout << "C++异常处理" << endl;
return 0;
}