多态
运算符重载
- 重载为类的非静态成员函数;
- 重载为非成员函数。
双目运算符重载为成员函数
- 如果要重载 B 为类成员函数,使之能够实现表达式 oprd1 B oprd2,其中 oprd1 为A 类对象,则 B 应被重载为 A 类的成员函数,形参类型应该是 oprd2 所属的类型。
- 经重载后,表达式 oprd1 B oprd2 相当于 oprd1.operator B(oprd2)
#include <iostream>
#include <cstdlib>
#include "Array.h"
using namespace std;
class Complex
{
private:
double real, img;
public:
Complex(double r=0, double i=0):real(r), img(i){}
Complex operator + (const Complex &c2) const;
Complex operator - (const Complex &c2) const;
void display() const;
};
Complex Complex::operator + (const Complex &c2) const
{
return Complex(real + c2.real, img + c2.img);
}
Complex Complex::operator - (const Complex &c2) const
{
return Complex(real - c2.real, img - c2.img);
}
void Complex::display() const
{
cout<<'('<<real<<", "<<img << ')'<<endl;
}
int main() {
Complex c1(5, 4), c2(2, 10), c3;
cout << "c1 = "; c1.display();
cout << "c2 = "; c2.display();
c3 = c1 - c2; //使用重载运算符完成复数减法
cout << "c3 = c1 - c2 = "; c3.display();
c3 = c1 + c2; //使用重载运算符完成复数加法
cout << "c3 = c1 + c2 = "; c3.display();
return 0;
}
单目运算符重载为成员函数
前置单目运算符重载规则
- 如果要重载 U 为类成员函数,使之能够实现表达式 U oprd,其中 oprd 为A类对象,则 U 应被重载为 A 类的成员函数,无形参。
- 经重载后,表达式 U oprd 相当于 oprd.operator U()
后置单目运算符 ++和--重载规则
- 如果要重载 ++或--为类成员函数,使之能够实现表达式 oprd++ 或 oprd-- ,其中 oprd 为A类对象,则 ++或-- 应被重载为 A 类的成员函数,且具有一个 int 类型形参。
- 经重载后,表达式 oprd++ 相当于 oprd.operator ++(0)
#include <iostream>
#include <cstdlib>
#include "Array.h"
using namespace std;
class Clock
{
private:
int hour, minute, second;
public:
Clock(int hour=0, int minute=0, int second=0);
Clock& operator ++ ();
Clock operator ++ (int);
void showTime() const{
cout << hour << ":" << minute << ":" << second << endl;
}
};
Clock::Clock(int hour, int minute, int second)
{
if (0 <= hour && hour < 24 && 0 <= minute && minute < 60
&& 0 <= second && second < 60)
{
this->hour = hour;
this->minute = minute;
this->second = second;
}
else{cout << "Time error" << endl;}
}
Clock& Clock::operator ++ ()
{
++second;
if (second >= 60) {
second -= 60; minute++;
if (minute >= 60) {
minute -= 60; hour = (hour + 1) % 24;
}
}
return *this;
}
Clock Clock::operator ++ (int)
{
Clock old = *this;
++(*this);
return old;
}
int main() {
Clock myClock(23, 59, 59);
cout << "First time output: ";
myClock.showTime();
cout << "Show myClock++: ";
(myClock++).showTime();
cout << "Show ++myClock: ";
(++myClock).showTime();
return 0;
}
运算符重载为非成员函数
有些运算符不能重载为成员函数,例如二元运算符的左操作数不是对象,或者是不能由我们重载运算符的对象,这是需要重载为非成员函数。
- 函数的形参代表依自左至右次序排列的各操作数。
- 重载为非成员函数时,参数个数=原操作数个数(后置++、--除外)
- 至少应该有一个自定义类型的参数。
- 后置单目运算符 ++和--的重载函数,形参列表中要增加一个int,但不必写形参名。
- 如果在运算符的重载函数中需要操作某类对象的私有成员,可以将此函数声明为该类的友元。
- 将<<(双目)重载为非成员函数,并将其声明为复数类的友元,它的左操作数是std::ostream引用,右操作数为复数类的常引用,返回std::ostream引用,用以支持下面形式的输出 :cout << a << b;
#include <iostream>
using namespace std;
class Complex {
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) { }
friend Complex operator+(const Complex &c1, const Complex &c2);
friend Complex operator-(const Complex &c1, const Complex &c2);
friend ostream & operator<<(ostream &out, const Complex &c);
private:
double real; //复数实部
double imag; //复数虚部
};
Complex operator+(const Complex &c1, const Complex &c2){
return Complex(c1.real+c2.real, c1.imag+c2.imag);
}
Complex operator-(const Complex &c1, const Complex &c2){
return Complex(c1.real-c2.real, c1.imag-c2.imag);
}
ostream & operator<<(ostream &out, const Complex &c){
out << "(" << c.real << ", " << c.imag << ")";
return out;
}
int main() {
Complex c1(5, 4), c2(2, 10), c3;
cout << "c1 = " << c1 << endl;
cout << "c2 = " << c2 << endl;
c3 = c1 - c2; //使用重载运算符完成复数减法
cout << "c3 = c1 - c2 = " << c3 << endl;
c3 = c1 + c2; //使用重载运算符完成复数加法
cout << "c3 = c1 + c2 = " << c3 << endl;
return 0;
}
虚函数
virtual关键字:进行动态绑定,不在编译期确定,而在执行的时候确定
virtual修饰的函数必须写在类外,不能写在类内,这成了内联函数,相矛盾
#include <iostream>
using namespace std;
class Base1 {
public:
virtual void display() const; //虚函数
};
void Base1::display() const {
cout << "Base1::display()" << endl;
}
class Base2:public Base1 {
public:
virtual void display() const;
};
void Base2::display() const {
cout << "Base2::display()" << endl;
}
class Derived: public Base2 {
public:
virtual void display() const;
};
void Derived::display() const {
cout << "Derived::display()" << endl;
}
void fun(Base1 *ptr) {
ptr->display();
}
int main() {
Base1 base1;
Base2 base2;
Derived derived;
fun(&base1);
fun(&base2);
fun(&derived);
return 0;
}
虚函数如何实现的?
-
虚表
-
- 每个多态类有一个虚表(virtual table)
- 虚表中有当前类的各个虚函数的入口地址
- 每个对象有一个指向当前类的虚表的指针(虚指针vptr)
-
动态绑定的实现
-
- 构造函数中为对象的虚指针赋值
- 通过多态类型的指针或引用调用成员函数时,通过虚指针找到虚表,进而找到所调用的虚函数的入口地址
- 通过该入口地址调用虚函数
抽象类
纯虚函数
-
纯虚函数是一个在基类中声明的虚函数,它在该基类中没有定义具体的操作内容,要求各派生类根据实际需要定义自己的版本,纯虚函数的声明格式为:
virtual 函数类型 函数名(参数表) = 0;
-
带有纯虚函数的类称为抽象类
抽象类
-
带有纯虚函数的类称为抽象类:
virtual 类型 函数名(参数表)=0;
-
只能作为基类使用,不能实例化对象
#include <iostream>
using namespace std;
class Base1 {
public:
virtual void display() const = 0; //纯虚函数
};
class Base2: public Base1 {
public:
virtual void display() const; //覆盖基类的虚函数
};
void Base2::display() const {
cout << "Base2::display()" << endl;
}
class Derived: public Base2 {
public:
virtual void display() const; //覆盖基类的虚函数
};
void Derived::display() const {
cout << "Derived::display()" << endl;
}
void fun(Base1 *ptr) {
ptr->display();
}
int main() {
Base2 base2;
Derived derived;
fun(&base2);
fun(&derived);
return 0;
}
override与final
override