多态性

C++
2024-12-25 09:01

一、多态的实现

  • 绑定机制:

    绑定是将一个标识符名和一个存储地址联系在一起的过程

  • 编译时的多态通过静态绑定实现

    绑定工作在程序编译连接阶段运行

  • 运行时的多态通过动态绑定实现

    绑定工作在程序运行阶段运行

二、运算符重载(静态绑定)

函数重载同样也是静态绑定

重载为类成员函数

函数类型  operator 运算符(形参) {        
		...... 
}

参数个数=原操作数个数-1 (后置++,-- 除外)

双目运算符重载规则 (1个参数 对象)

重载B为类成员函数,使之能够实现 oprd1 B oprd2;

+ 举例

经重载后,表达式 a + b 相当于 a.operator +(b)

Complex operator + (const Complex &c2) const;

Complex Complex::operator+(const Complex &c2){
	//创建一个临时无名对象作为返回值
	return Complex(real + c2.real, imag + c2.imag);

前置单目运算符重载规则(无参)

重载B为类成员函数,使之能实现 B oprd,无形参

前置++ 为例:

经重载后,++ a 相当于 a.operaotr ++()

Point &operator++();   //前置++

Point &Point::operator++(){
	x++;
	y++;
	//++a = b; => 左边的值先增加再做运算,所以返回修改后的值
	return *this;
}

后置单目运算符++和--重载规则 (1个参数 int)

如果要重载 ++ 或者 -- 为类成员函数,使之能够实现表达式 oprd ++ 或 oprd --,其中oprd为A类对象,则 ++ Huon -- 应该被重载为A类的成员函数,且具有一个 int 形参

后置++ 为例:

经重载后,a ++  相当于 a.operaotr ++(0)

Point operator++(int); //后置++

//后置运算符不能作为左值 a++ = b得到的a的值为a++的结果
Point Point::operator++(int)
{
    Point temp = *this;
    ++*this; //调用前置++
    //a++ = b; => 左边的值先做运算再增加,所以返回增加前的值(本身)
    return temp;
}

重载为非成员函数


参数个数=原操作数个数(后置++,-- 除外)

双目运算符重载规则(2个参数 对象)

两个操作数都是类的引用

friend Complex operator + (const Complex &c1, const Complex &c2);

前置单目运算符重载规则 (1个参数 对象)

friend Complex operator ++(Complex &c1);

后置单目运算符++和--重载规则 (2个参数 对象,0)

friend Complex operator ++(Complex &c1, 0);

三、运算符重载实例

对Point类重载++(自增)、--(自减)运算符,同时重载前缀和后缀形式

class Point
	{
	private:
	    int x, y;
	public:
	    Point(int a, int b)
	    {
	        x = a;
	        y = b;
	    }
	    Point &operator++();   //前置++
	    Point operator++(int); //后置++
	    Point &operator--();   //前置--
	    Point operator--(int); //后置--
	    int getx()
	    {
	        return x;
	    }
	    int gety()
	    {
	        return y;
	    }
	};
	Point &Point::operator++()
	{
	    x++;
	    y++;
	    //++a = b; => 左边的值先增加再做运算,所以返回修改后的值
	    return *this;
	}
	//后置运算符不能作为左值 a++ = b得到的a的值为a++的结果
	Point Point::operator++(int)
	{
	    Point temp = *this;
	    ++*this; //调用前置++
	    //a++ = b; => 左边的值先做运算再增加,所以返回增加前的值(本身)
	    return temp;
	}
	Point &Point::operator--()
	{
	    x--;
	    y--;
	    return *this;
	}
	Point Point::operator--(int)
	{
	    Point temp = *this;
	    --*this; //调用前置--
	    return temp;
	}

高精度算法:定义HugeInt类能处理20亿以上的整数并重载+和<<

32位整数的机器所能表示的整数范围大概是-20亿~20亿

思路:将大数存入数组,再对数组进行逐位操作

代码实现:👇

#include <cstring>
#include <string>
#include <iostream>
using std::ostream;

class HugeInt
{
public:
    HugeInt(long val = 0);            // long型数转换构造为HugeInt型
    HugeInt(const char *s);        // 字符存储的大数转换构造为HugeInt型
    HugeInt operator +(HugeInt &rhs);  // +重载
    friend ostream &operator <<(ostream &os, HugeInt &rhs); // <<重载
private:
    short integer[30];
};

// 转换构造函数
HugeInt::HugeInt(long val)
{
    for (int i = 0; i <= 29; i++)
        integer[i] = 0; // 将数组初始化为0
    for (int i = 29; val != 0 && i >= 0; i --)
    {//从后往前依次填入数组,不满30位的前面补0
        integer[i] = val % 10;
        val /= 10;
    }
}
HugeInt::HugeInt(const char *s)
{
    for (int i = 0; i <= 29; i++)
        integer[i] = 0;
    for (int i = 30 - strlen(s), j = 0; i <= 29; i++, j++)
        integer[i] = s[j]-'0';
}
// 巨型整数相加
HugeInt HugeInt::operator +(HugeInt &op2)
{
    HugeInt temp;
    int carry = 0; //进位
    for (int i = 29; i >= 0; i--)
    {
        temp.integer[i] = integer[i] + op2.integer[i] + carry;
        if (temp.integer[i] > 9)
        {
            temp.integer[i] %= 10;
            carry = 1;
        }
        else
            carry = 0;
    }
    return temp;
}
ostream &operator <<(ostream &output, HugeInt &num)
{
    int i = 0;
    for (; (num.integer[i] == 0) && (i <= 29); i++)
        ; // 跳过前导0
    if (i == 30)
        output << 0;
    else
        for (; i <= 29; i++)
            output << num.integer[i];
    return output;
}

int  main()
{
    using std::cout;
    using std::endl;
    HugeInt n1(7654321),n2(1234567);  //测试long型
    HugeInt n3("12345678987654321"), n4("12345678987654321"); //测试字符串型
    cout << "n1 is " << n1 << "\nn2 is " << n2 << "\nn3 is " << n3 << "\nn4 is " << n4 <<endl;
    HugeInt n5 = n1+n2;
    HugeInt n6 = n3+n4;
    HugeInt n7 = n3 + n1;
    cout<< "n1+n2="<<n5<<endl;  //测试long型大数相加
    cout<< "n3+n4="<<n6<<endl;  //测试字符串型大数相加
    cout<< "n1+n3=" << n7 << endl;  //测试long型和字符串型相加
}

四、虚函数(动态绑定)

初始虚函数


多态是不同对象对同一消息有不同的行为特性,虚函数作为运行过程中多态的基础,主要是针对对象的,而构造函数是在对象产生之前运行的,因此虚构造函数没有意义

一般虚函数成员


virtual 关键字


虚表与动态绑定


虚函数实例

定义一个基类BaseClass,从它派生出类DerivedClass,BaseClass有成员函数fn1()、fn2(),fn1()是虚函数,DerivedClass也有成员函数fn1()、fn2(),在主程序中定义一个DerivedClass的对象,分别用BaseClass和DerivedClass的指针来调用fn1()、fn2(),观察运行结果。

class BaseClass
{
public:
    virtual void fn1();
    void fn2();
};
void BaseClass::fn1()
{
    cout << "调用基类的虚函数fn1()" << endl;
}
void BaseClass::fn2()
{
    cout << "调用基类的非虚函数fn2()" << endl;
}
class DerivedClass : public BaseClass
{
public:
    void fn1();
    void fn2();
};
void DerivedClass::fn1()
{
    cout << "调用派生类的函数fn1()" << endl;
}
void DerivedClass::fn2()
{
    cout << "调用派生类的函数fn2()" << endl;
}
int main()
{
    DerivedClass aDerivedClass;
    DerivedClass *pDerivedClass = &aDerivedClass;
    BaseClass *pBaseClass = &aDerivedClass;
    pBaseClass->fn1();
    pBaseClass->fn2(); 
    pDerivedClass->fn1();
    pDerivedClass->fn2();
}


五、纯虚函数与抽象类


相关文章
热点文章
精彩视频
Tags

站点地图 在线访客: 今日访问量: 昨日访问量: 总访问量: