运算符重载
不能重载的运算符
- 类属关系运算符“.”
- 成员指针运算符“.*”
- 作用域分辨符“::”
- 三目运算符“?:”
重载运算符
重载运算符函数必须要有重载的类在参数里面
成员重载运算符
- 调用时,必须是类对象进行调用,且会将自己自动传入做this
- 双目运算符操作时,该类对象必须出现在左边,以进行调用
- 单目运算符操作时,int有是后置++/--,无是前置++/--
非静态成员
#include using namespace std; class Clock { public: Clock(int hour = 0, int minute = 0, int second = 0); void showTime() const; Clock &operator++(); //前置单目运算符 Clock operator++(int); //int用于区分前置还是后置运算符 后置单目运算符 private: int hour, minute, second; }; void Clock::showTime() const{ cout
非成员运算符
用来解决调用对象不是类对象的情况(但参数还是要有类对象存在)
非成员
#include 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
虚成员
虚函数
c++中有静态绑定和动态绑定,虚函数就是动态绑定
- 只有用virtual关键字特别声明的函数才进行动态绑定
- 虚函数必须是非静态的成员函数,虚函数经过派生之后仍然是虚函数
- 派生类中的虚函数还会隐藏基类中同名函数的所有其他重载形式(详见虚表)
- 派生类中可以对基类中的虚成员函数进行覆盖
- 虚函数不能是内联函数(内联函数是静态绑定)
- 当派生类的函数返回值和参数类型与个数和基类的虚函数一样时,该函数被默认为虚函数(即使没有书写virtual)
虚函数声明:
- 只能声明在类中的原函数处
- virtual 函数名(){}
虚函数
#include using namespace std; class A { public: virtual void func(); }; void A::func() { cout
虚析构函数
为什么需要虚析构函数?
- 可能通过基类指针删除派生类对象
- 如果你打算允许其他人通过基类指针调用对象的析构函数(通过delete这样做是正常的),就需要让基类的析构函数成为虚函数,否则执行delete的结果是不确定的
虚析构函数
#include #include using namespace std; class Base { public: virtual ~Base(); }; Base::~Base() { cout
void fun(Base *b){ delete b;//静态绑定,只会调用~Base() }
无论是虚函数还是虚析构函数,基类通过指针或者引用的情况才进行动态绑定,如果直接进行复制初始化,那么基类还是只调用基类的成员
虚表
虚表
- 每个多态类都有一个虚表
- 虚表中有当前类的各个虚函数的入口地址(不是声明了virtual该函数的入口地址就在虚表中)
- 每个对象有一个指向当前类的虚表的指针(虚指针vptr)
动态绑定的实现 - 构造函数中为对象的虚指针赋值
- 通过多态类型的指针或引用调用成员函数时,通过虚指针找到虚表,进而找到所调用的虚函数的入口地址
- 通过该入口地址调用虚函数
抽象类:纯虚函数
- 抽象类不用实现
- 其函数更像是目录
纯虚函数:
vitrual 函数类型 函数名(参数表) = 0;