遇到的问题:希望根据指针的指向(指向子类时),可以调用不同类中的函数(子类中的函数)
#include<iostream>
using namespace std;
class Parent {
public:
Parent(int a) {
this->a = a;
cout << "Parent构造 a:" << a << endl;
}
void print() {
cout << "Parent a: " << a << endl;
}
private:
int a;
};
class Child :public Parent {
public:
Child(int b) :Parent(10){
this->b = b;
cout << "Child构造 b:" << b << endl;
}
void print() { // 子类父类函数名一样
cout << "Child b: " << b << endl;
}
private:
int b;
};
void howToPrint(Parent* base) {
base->print();
}
void howToPrint2(Parent& base) {
base.print();
}
void main() {
Parent* base = NULL;
Parent p1(20);
Child c1(30);
base = &p1;
base->print(); // 执行父类打印函数
base = &c1;
base->print(); // 还是执行父类打印函数
{
Parent& base2 = p1;
base2.print();
Parent& base3 = c1;
base3.print(); // 还是执行父类打印函数
}
howToPrint(&p1);
howToPrint(&c1); // 还是执行父类打印函数
howToPrint2(p1);
howToPrint2(c1); // 还是执行父类打印函数
}
结果(全部调用父类函数)
Parent构造 a:20
Parent构造 a:10
Child构造 b:30
Parent a: 20
Parent a: 10
Parent a: 20
Parent a: 10
Parent a: 20
Parent a: 10
Parent a: 20
Parent a: 10
加入virtual 关键字
class Parent {
public:
Parent(int a) {
this->a = a;
cout << "Parent构造 a:" << a << endl;
}
virtual void print() {
cout << "Parent a: " << a << endl;
}
private:
int a;
};
class Child :public Parent {
public:
Child(int b) :Parent(10){
this->b = b;
cout << "Child构造 b:" << b << endl;
}
// 如果父类写了virtual关键字,子类可写可不写
virtual void print() { // 子类父类函数名一样
cout << "Child b: " << b << endl;
}
private:
int b;
};
结果
Parent构造 a:20
Parent构造 a:10
Child构造 b:30
Parent a: 20
Child b: 30
Parent a: 20
Child b: 30
Parent a: 20
Child b: 30
Parent a: 20
Child b: 30
1 面向对象三大概念
- 封装:突破C函数概念,用类做函数参数的时候,可以使用对象的属性和对象的方法
- 继承:A类 B继承A 实现代码复用
- 多态:可以不改变框架,增加新功能
2 多态使用条件
- 继承
- 虚函数重写
- 用父类指针指向子类对象
#include<iostream>
using namespace std;
class HeroFighter {
public:
virtual int power() {
return 10;
}
};
class EnemyFigher {
public:
int attack() {
return 15;
}
};
class AdvHeroFighter :public HeroFighter {
public:
virtual int power() {
return 20;
}
};
class AdvAdvHeroFighter :public HeroFighter {
public:
virtual int power() {
return 30;
}
};
// 多态
// 对象搭建平台 看作框架
void objplay(HeroFighter* hf, EnemyFigher* ef) {
if (hf->power() > ef->attack()) {
cout << "hero win" << endl;
}
else {
cout << "hero lose" << endl;
}
}
// 面向对象三大概念
// 封装:突破C函数概念,用类做函数参数的时候,可以使用对象的属性和对象的方法
// 继承:A类 B继承A 实现代码复用
// 多态:可以不改变框架,增加新功能
void main() {
HeroFighter hf;
AdvHeroFighter advhf;
AdvAdvHeroFighter advadvhf;
EnemyFigher ef;
// 改写多态
/*if (hf.power() > ef.attack()) {
cout << "hero win" << endl;
}
else {
cout << "hero lose" << endl;
}
if (advhf.power() > ef.attack()) {
cout << "hero win" << endl;
}
else {
cout << "hero lose" << endl;
}*/
objplay(&hf, &ef);
objplay(&advhf, &ef);
objplay(&advadvhf, &ef); // 不改变框架,可以继续使用
}
3 静态链编和动态链编
void objplay(HeroFighter* hf, EnemyFigher* ef) {
// 不写virtual是静态链编 C++编译器会根据HeroFighter类型执行函数,编译器编译阶段确定了函数调用
// 动态链编 迟绑定 virtual会在函数运行时根据具体对象类型执行不同对象的函数,表现为多态
if (hf->power() > ef->attack()) {
cout << "hero win" << endl;
}
else {
cout << "hero lose" << endl;
}
}
4 虚析构函数
只执行父类的析构函数
通过父类指针析构所有的子类资源
// 虚析构函数
class A {
public:
A() {
p = new char[20];
strcpy(p, "obja");
cout << "A构造函数" << endl;
}
virtual ~A() {
delete[] p;
cout << "A析构函数" << endl;
}
private:
char* p;
};
class B:public A {
public:
B() {
p = new char[20];
strcpy(p, "objb");
cout << "B构造函数" << endl;
}
virtual ~B() {
delete[] p;
cout << "B析构函数" << endl;
}
private:
char* p;
};
class C :public B {
public:
C() {
p = new char[20];
strcpy(p, "objc");
cout << "C构造函数" << endl;
}
virtual ~C() {
delete[] p;
cout << "C析构函数" << endl;
}
private:
char* p;
};
// 只执行父类的析构函数
// 通过父类指针析构所有的子类资源
void howToDelete(A *base){
delete base; // 不会表现为多态
}
void main() {
C* myc = new C;
// delete myc 直接释放子类不需要写virtual
howToDelete(myc);
}
5 重载重写重定义
函数重载
重载必须在同一个类中进行;子类无法重载父类函数,父类同名函数将被覆盖;重载是在编译期间根据参数类型和个数决定函数调用(静态联编)
函数重写
父类与子类之间;父类与子类中的函数必须有完全相同的原型;虚函数重写:virtual声明之后将产生多态;不用virtual重写叫做重定义;多态在运行期间根据函数具体的对象类型决定函数调用
#include<iostream>
using namespace std;
class Parent {
public:
virtual void func() {
cout << "func() do ..." << endl;
}
virtual void func(int i) {
cout << "func() do ..." << i << endl;
}
virtual void func(int i, int j) {
cout << "func() do ..." << i << " " << j << endl;
}
};
class Child:public Parent {
public:
virtual void func(int i, int j) {
cout << "func(i, j) do ..." << i << " " << j << endl;
}
virtual void func(int i, int j, int k) {
cout << "func(i, j, k) do ..." << i << " " << j << k << endl;
}
};
void main() {
Child c1;
// c1.func() // 报错 子类中存在func函数,不会调用父类中函数,使用时需要加上类作用域名字
c1.Parent::func();
}