1.函数重写
overload重载
override重写
函数重写只发生在父子类之间
在派生类中定义与基类函数原型相同(返回类型、函数名、参数列表)的函数
2.赋值兼容性原则
在基类与公有派生类之间也存在赋值兼容原则
is-a 关系
在需要父类对象的地方都可以用子类对象去替换
1.子类对象可以用来初始化父类对象
2.子类对象可以赋值给父类对象
3.父类指针可以指向子类对象
4.子类对象可以用来初始化父类引用
当函数重写遇上赋值兼容
int *p = new int(100);
cout << *P << endl;//???
-------------------------------------------------------------------------------------------------------
#include<iostream> using namespace std; class Parent { public: virtual void show() { cout << "Parent::show1()" << endl; } }; class Child:public Parent { public: virtual void show() { cout << "Child::show2()" << endl; } }; class Child3:public Parent { public: virtual void show() { cout << "Child::show3()" << endl; } }; void func(Parent* p) { p->show(); } int main() { Child c; c.show(); Parent p1 = c; p1.show();//1 2 Parent p2; p2 = c; p2.show();//? Parent &p3 = c; p3.show();//2 1 Parent *pp = &c; pp->show();//2,1 Child3 c3; func(&c3); func(&c); return 0; }
3.多态--接口重用
不同的对象收到相同的消息,产生不同的行为
在C++中,同类型(有共同的基类)的对象,调用函数名相同的函数,执行不同的功能
根据实现方式分为两类:
编译时多态:在编译阶段就能决定调用哪个函数,用函数重载、运算符重载实现
运行时多态:在运行阶段才能决定调用哪个函数,用继承和虚函数实现
虚函数:
被关键字virtual说明的函数,称为虚函数
如果基类中的某个函数被声明为虚函数,那么就希望该函数在派生类中有不同的行为, 那么就应该去重写基类的虚函数。
要相同的函数代码实现不同的算法!
运行时多态实现的条件:
继承 ,
虚函数,
指针/引用
虚函数的实现原理:
如果一个类中定义了虚函数,编译器会给该类型维护一个虚表(可以理解为一个数组),该虚表中的每个元素就是虚函数的地
址,标准C++规定应该要把这个虚表的首地址放置在该类型的每个对象实例的最前面,我们把这个地址称为虚指针
普通的成员函数(不包括构造函数和静态成员函数)可以声明为虚函数
-------------------------------------虚函数表------------------------------------------------------------------
#include<iostream> using namespace std; class Parent { virtual void show() { cout << "Parent::show1()" << endl; } virtual void print() { cout << "hello c++" << endl; } }; class Child:public Parent { void show() { cout << "Child::show2()" << endl; } }; class Child3:public Parent { public: void show() { cout << "Child::show3()" << endl; } }; void func(Parent* p) { // p->show(); } typedef void (*PFUN)(); int main() { cout << sizeof(Parent) << endl; cout << sizeof(Child) << endl; Child c; int *ptr = (int*)&c; cout << (int*)&c << endl; cout << ptr << endl; PFUN pf1 = 0; PFUN pf2 = 0; pf1 = (PFUN)*((int*)*(int*)&c); pf1(); pf2 = (PFUN)*((int*)*((int*)&c)+1); pf2(); return 0; }
虚析构函数:
析构函数也可以声明为虚函数,称为虚析构函数
建议把基类的析构函数设置为虚函数!
-------------------------------------虚析构函数------------------------------------------------------------------
#include<iostream> using namespace std; class Parent { public: Parent() { pp = new char[100]; } virtual void show() { cout << "Parent::show1()" << endl; } virtual void print() { cout << "hello c++" << endl; } virtual ~Parent() { cout << "~Parent()" << endl; delete []pp; } private: char *pp; }; class Child:public Parent { public: Child() { pc = new char[1024]; } virtual ~Child() { cout << "~Child()" << endl; delete []pc; } virtual void show() { cout << "Child::show2()" << endl; } private: char *pc; }; int main() { Child c; Parent *p1 = &c; p1->show(); Parent *p2 = new Child; p2->show(); delete p2; cout << "-------------" << endl; return 0; }
纯虚函数与抽象类:
如果一个类中的虚函数希望派生类去重新实现,且在基类中不知道怎么实现或不应该实现
,那么就可以把这种虚函数设置成纯虚函数。
纯虚函数格式:
virtual 返回类型 函数名()=0;
注意:
=0 是告诉编译器,该函数没有实现,
希望子类自己去实现,如果子类不实现该函数,会自动继承过去
如果一个类中包含纯虚函数,该类就称为抽象类!
抽象类不能用来实例化对象!
但是可以创建抽象类型的指针!
-------------------------------------抽象类------------------------------------------------------------------
#include<iostream> using namespace std; class Che { public: void run(); virtual void stop()=0;//纯虚函数 private: string brand; int price; }; class Bike:public Che { public: virtual void stop() { cout << "1.用手握紧刹车,2,用脚踩地" << endl; } private: }; class Car:public Che { public: virtual void stop() { cout << "用脚踩刹车,然后再拉手刹!" << endl; } }; void func(Che *p) { p->stop(); } int main() { Bike bike; bike.stop(); Car car; func(&bike); func(&car); return 0; }