C++程序设计 第八章 多态性

运算符重载

双目运算符重载为成员函数

函数类型 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值