多态是面向对象的三大特性之一,说的是同一个事物有不同的行为。
多态可分为:
#include
using namespace std;
class Father {
public:
virtual void func() {
cout << "father func" << endl;
}
//void func() {
// cout << "father func" << endl;
//}
};
class Son : public Father {
public:
void func() {
cout << "son func" << endl;
}
};
void test(Father &father) {
father.func();
}
int main() {
Father father;
father.func();
Son son;
son.func();
test(father);
test(son);
return 0;
}
输出
未使用virtual
father func
son func
father func
father func
使用virtual
father func
son func
father func
son func
使用自己的对象调用方法,则是和继承里面的处理相同。如果存在同名函数,子类直接调用为子类的函数,使用作用域限定符调用父类的函数。
如果没有virtual修饰,即使有父类引用指向子类对象,调用的也是父类的同名函数,而不会体现出多态行为。
而将父类的函数标记为virtual之后,就能使继承中存在多态关系,多态需满足条件:
使用多态实现一个计算器类
普通实现:
#include
using namespace std;
class Calculator {
public:
int getResult(string oper) {
if (oper == "+") {
return m_Num1 + m_Num2;
} else if (oper == "-") {
return m_Num1 - m_Num2;
} else if (oper == "*") {
return m_Num1 * m_Num2;
}
//如果要提供新的运算,需要修改源码
}
public:
int m_Num1;
int m_Num2;
};
void test01() {
Calculator c;
c.m_Num1 = 10;
c.m_Num2 = 10;
cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.getResult("+") << endl;
cout << c.m_Num1 << " - " << c.m_Num2 << " = " << c.getResult("-") << endl;
cout << c.m_Num1 << " * " << c.m_Num2 << " = " << c.getResult("*") << endl;
}
int main() {
test01();
return 0;
}
普通实现,通过判断来实现,如果需要新增算法,则需要改动类,对于类的封装性和扩展性都不好。
如果有了多态,可以这样实现:
#include
using namespace std;
class AbstractCalculator {
public:
virtual int getResult() {
return 0;
}
int m_num1;
int m_num2;
};
class AddCalculator : public AbstractCalculator {
public:
int getResult() override {
return m_num1 + m_num2;
}
};
class SubCalculator : public AbstractCalculator {
int getResult() override {
return m_num1 - m_num2;
}
};
class MulCalculator : public AbstractCalculator {
int getResult() override {
return m_num1 * m_num2;
}
};
void test() {
AbstractCalculator *abc = new AddCalculator;
abc->m_num1 = 10;
abc->m_num2 = 10;
cout << abc->m_num1 << " + " << abc->m_num2 << " = " << abc->getResult() << endl;
delete abc;
abc = new SubCalculator;
abc->m_num1 = 10;
abc->m_num2 = 10;
cout << abc->m_num1 << " - " << abc->m_num2 << " = " << abc->getResult() << endl;
delete abc;
abc = new MulCalculator;
abc->m_num1 = 10;
abc->m_num2 = 10;
cout << abc->m_num1 << " * " << abc->m_num2 << " = " << abc->getResult() << endl;
delete abc;
}
int main() {
test();
return 0;
}
通过继承和多态来实现,封装性和扩展性都要更强一些。
在多态中,通常父类中的虚函数没有实现,提供给子类重写,所以可以设置成纯虚函数
当类中有纯虚函数,这个类称为抽象类
抽象类的特点:
#include
using namespace std;
class Father {
public:
virtual void func() = 0;
};
class Son : public Father {
public:
virtual void func() {
cout << "Son func" << endl;
}
};
void test() {
// Father father;
Father *father;
father = new Son;
father->func();
delete father;
}
int main() {
test();
return 0;
}
输出
Son func
多态使用时,如果子类有属性开辟到堆区,那么父类指针释放的时候无法调用到子类的析构函数
#include
using namespace std;
class Father {
public:
virtual void func() = 0;
};
class Son : public Father {
public:
~Son() {
cout << "Son deconstructor" << endl;
}
virtual void func() {
cout << "Son func" << endl;
}
};
void test() {
Father *father;
father = new Son;
father->func();
delete father;
}
int main() {
test();
return 0;
}
输出:
Son func
没有子类析构函数的打印
对于此问题,可以将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
虚析构和纯虚析构区别:
#include
using namespace std;
class Father {
public:
virtual void func() = 0;
virtual ~Father() {
cout << "Father deconstructor" << endl;
}
// virtual ~Father() = 0;
};
// Father::~Father() {
// cout << "Father deconstructor" << endl;
// }
class Son : public Father {
public:
~Son() {
cout << "Son deconstructor" << endl;
}
virtual void func() {
cout << "Son func" << endl;
}
};
void test() {
Father *father;
father = new Son;
father->func();
delete father;
}
int main() {
test();
return 0;
}
输出
Son func
Son deconstructor
Father deconstructor
此时子类析构函数被调用,可以在子类析构中进行动态内存释放。