多态性的两种类型
- 静态多态性
- 编译时
- 静态联编
- 函数/运算符重载
- 动态多态性
- 运行时
- 动态联编
- 继承、虚函数、基类的指针或引用
- 在编译时无法确定调用的是哪个同名函数
静态多态性
缺点:不够灵活
优点:调用速度快,效率高
- 函数重载
- 同一个类中多个成员函数
- 基类和派生类中的同名函数之间
同一个类中多个成员函数
#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;
}