多态性的两种类型
- 静态多态性
- 编译时
- 静态联编
- 函数/运算符重载
- 动态多态性
- 运行时
- 动态联编
- 继承、虚函数、基类的指针或引用
- 在编译时无法确定调用的是哪个同名函数
静态多态性
缺点:不够灵活
优点:调用速度快,效率高
- 函数重载
- 同一个类中多个成员函数
- 基类和派生类中的同名函数之间
同一个类中多个成员函数
#include <iostream> #include <string> using namespace std; class Student { private: string name; int sort; public: Student(); Student(string sname, int n); void print(); void print(int n); }; Student::Student() { name = "Unknown"; sort = 18; } Student::Student(string sname, int n) { name = sname; sort = n; } void Student::print() { cout << "Name: " << name << endl; cout << "Sort: " << sort << endl; } void Student::print(int n) { cout<<"Number: "<< n << sort <<endl; } int main() { Student s1; Student s2("John", 20); s1.print(); s2.print(); s2.print(2024); return 0; }
基类和派生类中的同名函数之间
#include <iostream> using namespace std; class A { public: double get_value(double a,double b) { return a; } }; class B: public A { public: double get_value(double c) { return c; } }; int main() { A obj1; B obj2; cout<<obj1.get_value(2.5,3.5)<<endl; cout<<obj2.get_value(3.2)<<endl; cout<<obj2.A::get_value(4.7,2.6)<<endl; return 0; }
运算符重载
本质是函数重载
对已有 运算符赋予多重含义,同一个运算符作用于不同类型的数据将会产生不同的行为
不可以重载的运算符:
. 成员提取符
.* 成员指针运算符
:: 作用域修饰符
?: 条件运算符
sizeof 长度运算符
重载之后,运算符的优先级和结合性都不会改变
运算符重载不能改变原运算符的操作对象个数,且至少要有一个操作对象属于自定义类型
运算符重载方式:类中成员函数,类的友元函数
只能成员函数:=,(),[],->
只能友元函数:提取符>>,插入符<<
用成员函数重载运算符
第一运算对象必须是本类的对象,否则只能通过友元函数重载
#include <iostream> using namespace std; class Complex { private: float real; float imag; public: Complex(float r = 0, float i = 0); void print(); Complex operator + (const Complex& a); Complex operator + (float x); Complex operator ++ (); //单目不需要形参 }; Complex::Complex(float r, float i) { real = r; imag = i; } void Complex::print() { cout << real; if (imag != 0) { if (imag > 0) cout << "+"; cout << imag << "i"; } cout << endl; } Complex Complex::operator+(const Complex& a) //形参为第二运算对象 { Complex temp; temp.real = real + a.real; temp.imag = imag + a.imag; return temp; } Complex Complex::operator+(float x) { return Complex(real+x,imag+x); //虚部和实部同时加x } Complex Complex::operator++() { ++real; ++imag; return *this; } int main() { Complex c1(1.5, 2.5), c2(5, 10), c3, c4; cout << "original c1 is:" ; c1.print(); cout << "original c2 is:"; c2.print(); c3 = c1 + c2; cout << "c3=c1+c2 is:"; c3.print(); c3 = c3 + 5.32f; cout << "c3+5.32f is:"; c3.print(); c4 = ++c2; cout << "after ++c2 c2 is:"; c2.print(); cout << "after ++c2 c4 is:"; c4.print(); return 0; }
用友元函数重载运算符
第一个操作数不是本类对象
提取运算符 >>
插入运算符 <<
#include <iostream> using namespace std; class Complex { private: float real, imag; public: Complex(float r=0,float i=0); void print(); friend Complex operator+(const Complex &a,const Complex &b); friend Complex operator+(const Complex &a,float x); friend Complex operator++(Complex &a); }; Complex::Complex(float r,float i) { real=r; imag=i; } void Complex::print() { cout<<real; if (imag!=0) { if (imag>0) cout<<"+"; cout<<imag<<"i"<<endl; } cout<<endl; } Complex operator+(const Complex &a,const Complex &b) { Complex temp; temp.real=a.real+b.real; temp.imag=a.imag+b.imag; return temp; } Complex operator+(const Complex &a,float x) { return Complex(a.real+x,a.imag+x); } Complex operator++(Complex &a) { ++a.real; ++a.imag; return a; } int main() { Complex c1(1.5,2.5),c2(5,10),c3,c4; cout<<"original c1:"; c1.print(); cout<<"original c2:"; c2.print(); c3=c1+c2; cout<<"c3=c1+c2:"; c3.print(); c3=c3+5.32f; cout<<"c3=c3+5.32f:"; c3.print(); c4=++c2; cout<<"after ++c2,c2:"; c2.print(); cout<<"after ++c2,c4:"; c4.print(); return 0; }
赋值运算符"="重载
只能被重载为成员函数
不能被继承
运算对象非基本类型时,应当给出 ”=“ 运算符重载函数
#include<iostream> using namespace std; class CMessage { private: char* pmessage; public: CMessage(const char* text = "爱我中华!") { pmessage = new char[strlen(text) + 1]; strcpy_s(pmessage, strlen(text) + 1, text); } void show() { cout << pmessage << endl; } ~CMessage() { cout << "Destructor called." << endl; delete[] pmessage; } CMessage& operator=(const CMessage& s); }; CMessage& CMessage::operator=(const CMessage& s) { int len = strlen(s.pmessage) + 1; if (pmessage) delete[] pmessage; pmessage = new char[len]; strcpy_s(pmessage, len, s.pmessage); return *this; } int main() { CMessage msg1("中国一点也不能少!"); CMessage msg2; msg1.show(); msg2.show(); cout << "after msg2=msg1 >>>> " << endl; msg2 = msg1; msg1.show(); msg2.show(); return 0; }
下标运算符"[]"的重载
可以带一个右操作数
只能使用成员函数
#include<iostream> #include<iomanip> using namespace std; class Array { private: int* m; int num; public: Array(int n=3); ~Array(); int& operator[](int); void show(); }; Array::Array(int n) { num = n; m = new int[num]; if (m == NULL) { cout << "allocation failure." << endl; exit(0); } for (int i = 0; i < num; i++) m[i] = i * 10 + 1; //为数组的每个元素赋初值 } Array::~Array() { delete[] m; } void Array::show() { for (int i = 0; i < num; i++) cout << setw(4) << m[i]; cout << endl; } int& Array::operator[](int r) { if (r > 0 && r < num) return *(m + r); return *m; } int main() { Array ar(5); ar.show(); ar[2] = 800; ar.show(); ar[23] = -100; ar.show(); return 0; }
自增自减运算符重载
#include <iostream> using namespace std; class Complex { private: float real, imag; public: Complex (float r=0, float i=0); Complex operator --(); Complex operator --(int); friend Complex operator ++(Complex& a); friend Complex operator ++(Complex& a, int); friend istream& operator >> (istream& in, Complex& com); friend ostream& operator << (ostream& out, const Complex& com); }; Complex::Complex(float r, float i) { real = r; imag = i; } Complex Complex::operator --() { real--; imag--; return *this; } Complex Complex::operator --(int) { Complex temp = *this; real--; imag--; return temp; } Complex operator ++(Complex& a) { a.real++; a.imag++; return a; } Complex operator ++(Complex& a, int) { Complex temp = a; a.real++; a.imag++; return temp; } istream& operator >> (istream& in, Complex& com) { in >> com.real >> com.imag; return in; } ostream& operator << (ostream& out, const Complex& com) { out << com.real ; if(com.imag != 0) { if(com.imag > 0) out << "+"; out << com.imag << "i"; } out << endl; return out; } int main() { Complex c1(1.5,-2.5),c2(-5,10),c3,c4; cout<<"original c1 = "<<c1; cout<<"original c2 = "<<c2; c3 = ++c2; cout<<"after c3 = ++c2 "; cout<<"c2 = "<<c2; cout<<"c3 = "<<c3; c4=--c2; cout<<"after c4=--c2 "; cout<<"c2 = "<<c2; cout<<"c4 = "<<c4; c3=c1++; cout<<"after c3=c1++ "; cout<<"c1 = "<<c1; cout<<"c3 = "<<c3; c4=c1--; cout<<"after c4=c1-- "; cout<<"c1 = "<<c1; cout<<"c4 = "<<c4; return 0; }
提取运算符">>"和插入运算符"<<"的重载
第一操作数是流对象,只能以友元函数实现
两个形参,第一个必须为输入流 istream 的引用,第二个必须为本类的对象引用,不可以用常引用或值形式参数
两个形参,第一个必须为 输出流 ostream 的引用,第二个必须为本类的对象引用,一般用常引用参数,保护对应实参和提高效率
必须返回流类的引用
#include <iostream> using namespace std; class Complex { private: float real, imag; public: Complex(float r=0, float i=0); friend istream & operator>>(istream &in, Complex &c); friend ostream & operator<<(ostream &out, Complex &c); }; Complex::Complex(float r, float i) { real = r; imag = i; } istream & operator>>(istream &in, Complex &c) { in >> c.real >> c.imag; return in; } ostream & operator<<(ostream &out, Complex &c) { out << c.real; if(c.imag >= 0) out << "+" ; out << c.imag << "i"; out << endl; return out; } int main() { Complex c1(1.5, 2.5); Complex c2; cout<<"c1 = "; cout<<c1; cout<<"c2 = "<<c2; //cout<<(operator<<(cout, "c2=")<<c2; cout<<"input c1, c2: "; cin>>c1>>c2; cout<<"c1 = "<<c1; cout<<"c2 = "<<c2; return 0; }
动态多态性的实现
虚函数的定义
具有继承关系(必须公有继承)
基类与派生类中的同名函数,且函数头部完全一致
必须与引用/指针一起使用
符合赋值兼容规则
静态成员不能声明为虚函数
内联函数不能声明为虚函数
构造函数不能是虚函数
析构函数可以是虚函数,且往往被声明为虚函数
虚析构函数
若基类的析构函数声明为虚函数,则该类的所有派生类的析构函数也自动成为虚函数而无需显式声明
#include <iostream> using namespace std; class Base { public: virtual ~Base(); }; class Derived : public Base { private: char *str; public: Derived(int x); ~Derived(); }; Base::~Base() { cout << "Base destructor called" << endl; } Derived::Derived(int x) { str = new char[x]; } Derived::~Derived() { delete[] str; cout << "Derived destructor called" << endl; } int main() { Base *b = new Derived(10); delete b; return 0; }
虚函数与同名覆盖
#include <iostream> using namespace std; class Base { public: virtual void f1() { cout<<"f1 function of Base"<<endl; } virtual void f2() { cout<<"f2 function of Base"<<endl; } void f3() { cout<<"f3 function of Base"<<endl; } }; class Derived : public Base { public: void f1() { cout<<"f1 function of Derived"<<endl; } void f2(int x) { cout<<"f2 function of Derived "<<endl; } void f3() { cout<<"f3 function of Derived"<<endl; } }; int main() { Base ob1,*b; Derived ob2; b=&ob1; cout<<"Base ob1"<<endl; b->f1(); b->f2(); b->f3(); cout<<"Derived ob2"<<endl; b=&ob2; b->f1(); b->f2(); b->f3(); cout<<"f1,f2,f3 functions of Derived"<<endl; ob2.f1(); ob2.f2(5); ob2.f3(); return 0; }
用派生类对象调用函数,发生同名时只能调用自身的成员函数
纯虚函数与抽象类
纯虚函数
只给出了函数的原型声明而没有具体的实现内容
在虚函数原型的最后赋值0
没有函数体
不能被调用
作用:基类给派生类提供一个标准的函数原型
#include <iostream> using namespace std; class Point { public: virtual void Draw()=0; }; class Line : public Point { public: void Draw(); }; void Line::Draw() { cout << "Drawing a line" << endl; } class Circle : public Point { public: void Draw(); }; void Circle::Draw() { cout << "Drawing a circle" << endl; } //functions void DrawObject(Point* p) { p->Draw(); } int main() { Line l; Circle c; DrawObject(&l); DrawObject(&c); return 0; }
抽象类
至少包含一个纯虚函数的类
不能生成对象
可以定义抽象类的指针或引用
不能作为参数类型、函数返回类型、显式转换类型
基类不能是普通类
还可以定义普通成员函数或虚函数
#include <iostream> using namespace std; const double pi = 3.14; class Shape { public: virtual double area() const=0; }; //三角形 class Triangle : public Shape { private: double base, height; public: Triangle(double b,double h) : base(b), height(h) {} double area() const; }; //矩形 class Rectangle : public Shape { private: double height, width; public: Rectangle(double h,double w) : height(h), width(w) {} double area() const; }; //圆形 class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} double area() const; }; //函数实现 //三角形 double Triangle::area() const { return 0.5 * base * height; } //矩形 double Rectangle::area() const { return height * width; } //圆形 double Circle::area() const { return pi * radius * radius; } //主函数 int main() { Shape *ptr[3]; ptr[0] = new Triangle(2.5, 10); ptr[1] = new Rectangle(15, 22); ptr[2] = new Circle(3.0); cout << "Area of Triangle: " << ptr[0]->area() << endl; cout << "Area of Rectangle: " << ptr[1]->area() << endl; cout << "Area of Circle: " << ptr[2]->area() << endl; delete ptr[0]; delete ptr[1]; delete ptr[2]; return 0; }