多态及运算符重载
C++ 多态的定义及实现
1. 多态定义的构成条件
多态是在不同继承关系的类对象,去调同一函数,产生了不同的行为。
就是说,有一对继承关系的两个类,这两个类里面都有一个函数且名字、参数、返回值均相同,然后我们通过调用函数来实现不同类对象完成不同的事件。
但是构成多态还有两个条件:
调用函数的对象必须是指针或者引用。
被调用的函数必须是虚函数,且完成了虚函数的重写。
2.析构函数重写问题
基类中的析构函数如果是虚函数,那么派生类的析构函数就重写了基类的析构函数。这里他们的函数名不相同,看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor,这也说明的基类的析构函数最好写成虚函数。
将析构函数定义为虚函数的原因:
因为基类指针可能指向派生类,当delete的时候,如果不定为虚函数,系统会直接调用基类的析构函数,这个时候派生类就有一部分没有被释放,就会造成可怕的内存泄漏问题。
若定义为虚函数构成多态,那么就会先调用派生类的析构函数然后派生类的析构函数会自动调用基类的析构函数,这个结果满足我们的本意。
所以!在继承的时候,尽量把基类的析构函数定义为虚函数,这样继承下去的派生类的析构函数也会被变成虚函数构成多态。
3.抽象类
在虚函数的后面写上 =0 ,则这个函数就变成纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。
这个纯虚函数的作用就是强迫我们重写虚函数,构成多态。这样更加体现出了接口继承。
运算符重载:友元函数形式的运算符重载:
单目:
#include <ostream> #include <iostream> using namespace std; class CCounter { public: CCounter() { m_nValue = 0; }; friend void operator++(CCounter &obj) { //1th 由于友元函数不属于此类,故这里要加引用符号 if (obj.m_nValue < 65535) { obj.m_nValue++; } } int operator*() { //2th return m_nValue; } private: int m_nValue; }; int main() { CCounter objA; ++objA; //隐式,调用1th operator++(objA);//显示调用1th,这里需要加objA,这里与1th处与成员函数运算符重载不同!!! cout << *objA << endl; //调用2th处函数 return 0; }
双目:
#include <iostream> using namespace std; class CCounter { public: CCounter(int nNum) { m_nValue = nNum; }; friend void operator+(CCounter &objA,CCounter objB) { //1th 由于友元函数不属于此类,故这里要加引用符号 //这里第二个&可以不用加! objA.m_nValue+=objB.m_nValue; } friend int operator*(CCounter obj) { //2th return obj.m_nValue; } private: int m_nValue; }; int main() { CCounter objA(5),objB(6); objA+objB; //隐式,调用1th operator+(objA,objB);//显示调用1th,这里需要加objA,这里与1th处与成员函数运算符重载不同!!! cout << *objA << endl; //调用2th处函数 return 0; }
特殊符号:
#include <iostream> using namespace std; class CCounter { public: CCounter(int nNum) { m_nValue = nNum; } CCounter(CCounter &obj) { m_nValue = obj.m_nValue; } CCounter& operator=(CCounter &obj) { //1th m_nValue = obj.m_nValue; return *this; } int operator *() { return m_nValue; } private: int m_nValue; }; int main() { CCounter objA(15), objB(5); objA = objB; //隐式,调用1th cout << *objA << endl; //调用2处函数 return 0; }
特殊运算符重载:
#include <iostream> using namespace std; class CCounter { public: CCounter() { memset(m_szStr, 0, sizeof(m_szStr));//0th } friend ostream& operator<<(ostream& output, CCounter &obj) {//1th output << obj.m_szStr; return output; } friend istream& operator>>(istream& input, CCounter &obj) {//2th input.getline(obj.m_szStr, 15);//获取一行的数据(这里指字母或者数字的个数,包括'\0') //输入的个数大于15,只是获取前面15个!!! return input; } private: char m_szStr[15]; }; int main() { CCounter obj; //调用0th处的构造函数 cin >> obj; //调用2th cout << obj; //调用1th return 0; }