.1多态的基本概念
- 静态多态:函数重载以及运算符重载。函数地址早绑定–编译阶段确定函数地址
- 动态多态:派生类和虚函数实现运行时多态。函数地址晚绑定–运行阶段确定函数地址
动态多态满足条件: 1.有继承关系 2.子类重写父类中的虚函数 3.父类的指针或引用,执行子类的对象
class Animal {
public:
virtual void speak() {
cout << "动物说话" << endl;
}
};
class Dog :public Animal{
public :
void speak(){
cout << "狗说话" << endl;
}
};
void dospeak(Animal &animal) {
animal.speak();
}
void test() {
Dog p;
dospeak(p);
}
内部原理: 当子类重写父类函数时,会用子类虚函数表覆盖掉父类的虚函数表,从而在动态多态调用 指针实现多态:
class Calculator {
public :
virtual int getre() {
return 0;
}
int m_num1;
int m_num2;
};
class add : public Calculator {
public:
int getre() {
return m_num1 + m_num2;
}
};
class sub : public Calculator {
public:
int getre() {
return m_num1 - m_num2;
}
};
void test() {
Calculator* abs = new add;
cout << abs->getre() << endl;
delete abs;
}
.2纯虚函数和抽象类
由于在多态中,父类中虚函数实现无意义,可以改成纯虚函数virtual 返回类型 函数名 (参数) = 0; 同时父类称为抽象类 抽象类特点:
- 无法实例化对象
- 抽象类的子类必须重写父类中的纯虚函数,否则也属于抽象类
实例:
class Abs {
public :
virtual void step1() = 0;
virtual void step2() = 0;
void getresult() {
step1();
step2();
}
};
class Son1 :public Abs {
public:
void step1() {
cout << "Son1执行第一步" << endl;
}
void step2() {
cout << "Son1执行第二步" << endl;
}
};
void test() {
Abs* p = new Son1;
p->getresult();
delete p;
}
.3虚析构和纯虚析构
使用多态时,如果子类中有属性开辟到堆区,父类指针释放时无法调用子类析构代码
class Abs {
public :
Abs() {
cout << "Abs构造函数调用" << endl;
}
~Abs() {
cout << "Abs析构函数调用" << endl;
}
};
class Son :public Abs {
public:
Son(string name) {
cout << "son构造函数调用" << endl;
m_name = new string(name);
}
~Son() {
cout << "son析构函数调用" << endl;
if (m_name != NULL) {
delete m_name;
m_name = NULL;
}
}
string* m_name;
};
void test() {
Abs* p = new Son("zsd");
delete p;
}
子类堆区数据未释放,有两种方法解决:
class Abs {
public :
Abs() {
cout << "Abs构造函数调用" << endl;
}
virtual ~Abs() = 0 ;
};
class Abs {
public :
Abs() {
cout << "Abs构造函数调用" << endl;
}
virtual ~Abs() = 0 ;
};
Abs::~Abs() {
}
总结: 1.虚析构或纯虚析构是用来解决通过父类指针释放子类对象 2.如果子类中没有堆区数据,可以不写 3.拥有纯虚析构函数的类也属于抽象类
|