运算符重载
双目运算符重载为成员函数
函数类型 opetator 运算符(形参)//双目运算符形参里面只有一参数为第二个操作数
{
...
}
oprd1 B oprd2 相当于 oprd.operator B(oprd2)
即B应该被重载为双目运算符前者的成员函数,该函数形参应该为双目运算符后者
重载+实现复数加法运算
类内定义:
Complex operator + (const Complex &c2)const;
//operator + 视为函数名,形参引用加const限定,不改变类数据的成员函数一律可以加const限定
Complex Complex::operator + (const Complex &c2)const{
return Complex(real+c2.real,imag+c2.imag);
//返回一个临时新初始化的Complex对象作为返回值
}
单目运算符重载为成员函数
前置单目运算符:
U oprd 相当于oprd.operator U()
定义:Clock& operator ++ ();
实现:Clock & Clock::operator ++ () {
second++;
if (second >= 60) {
second -= 60; minute++;
if (minute >= 60) {
minute -= 60; hour = (hour + 1) % 24;
}
}
return *this;
}
后置单目运算符:为了与前置区分,参数表需要比前置多一个参数
oprd ++ 相当于 oprd.oprator U(0)
定义:Clock operator ++ (int);
实现:Clock Clock::operator ++ (int) {
//注意形参表中的整型参数
Clock old = *this;
++(*this); //调用前置“++”运算符
return old;
}
前置单目运算符返回对象本身,是一个左值
后置单目运算符返回的old是原来的对象的副本,是一个右值,不能改变对象
运算符重载为非成员函数
当运算符左操作数不是类对象如实数+虚数,或者做操作数不是自己定义的类的时候,需要将运算符重载为非成员函数,且申明为类的友元
双目:
oprd1 B oprd2
等同于 operator B(oprd1,oprd2)
前置单目:
B oprd
等同于 operator B(oprd)
后置单目
oprd B
等同于 operator B(oprd,0)
重载<<实现复数输出
定义:friend ostream & operator <<(ostream &out,const Complex &c);
实现:ostream & operator <<(ostream &out,const Complex &c){
out<<"(" << c.real << ", " << c.imag << ")";
return out;
\\返回一个流对象,这样可以实现级联的输出
}
虚函数
虚函数:通过虚函数实现运行时多态(动态绑定,运行时决定调用哪个类函数,可以实现在派生类函数中对基类函数的覆盖)
C++中多态就是通过虚函数来实现的
虚函数的实现是由两个部分组成的,虚函数指针与虚函数表
父类的指针或引用有多种形态,可以使用一个父类的指针或引用统一操作各种子类对象。为了实现动态绑定,编译器会在为每一个包虚函数的类提供一个虚函数表,这个虚函数表被一个虚函数指针指向,这个类的虚函数表包含一个数组用于存放虚函数的地址,每一个指针指向了类中的虚函数。
当虚函数被调用时,编译器会使用该对象中的虚指针来查找虚函数表,然后遍历虚函数表,以查找虚函数的指针 (地址),最终找到正确版本的函数。
#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;
}
fun()中定义的父类Base1的引用,却可以直接给fun()传子类的引用
可以通过父类的指针调用子类的函数,这就是运行时的多态
虚析构函数:构造函数不可以是虚函数,析构函数常常是虚函数(在有继承的情况下)。当要使用基类指针或引用调用子类时,若析构函数不是虚函数,delete时只释放基类,不释放子类,会存在内存泄露的问题。
抽象类
纯虚函数形式:virtual 函数原型=0;
在基类中声明的虚函数,它在该基类中没有定义具体的操作,要求各派生类根据自己的实际需要定义自己的版本,类似于java的接口
声明了纯虚函数的类,都称为抽象类
1)抽象类只能作为基类使用
2)不能定义抽象类对象
可以声明指向抽象类的指针变量或引用变量指向派生类对象,通过指针或引用,就可以指向并访问派生类对象,进而访问派生类的成员。(体现了多态性)
#include <iostream>
using namespace std;
//定义一个形状抽象类
class Shape
{
protected:
double x;
double y;
public:
void set(double i, double j)
{
x = i;
y = j;
}
virtual void area() = 0; //定义纯虚函数,用来某形状计算面积
};
//定义一个矩形类
class Rectangle :public Shape
{
//具体实现方法
void area()
{
cout << x * y << endl; //x和y为矩形的长和宽
}
};
//定义一个直角三角型类
class Triangle :public Shape
{
//具体实现方法
void area()
{
cout << x * y * 0.5 << endl; //x和y为直角三角形的直角边
}
};
int main()
{
Rectangle rec; //定义一个矩形对象
Triangle tri; //定义一个直角三角型对象
Shape *p = &rec; //定义一个抽象类的指针p,并使它指向矩形对象
p->set(2, 4); //调用矩形类中的设置参数方法
p->area(); //调用矩形类中计算矩形面积的方法
p = &tri; //让指针p指向直角三角形对象
p->set(2, 4); //调用直角三角形类中的设置参数方法
p->area(); //调用直角三角形类中计算面积的方法
system("pause");
return 0;
}