一、多态的实现
绑定机制:
绑定是将一个标识符名和一个存储地址联系在一起的过程
编译时的多态通过静态绑定实现
绑定工作在程序编译连接阶段运行
运行时的多态通过动态绑定实现
绑定工作在程序运行阶段运行
二、运算符重载(静态绑定)
函数重载同样也是静态绑定
重载为类成员函数
函数类型 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();
}