8_多态

多态

运算符重载

  • 重载为类的非静态成员函数;
  • 重载为非成员函数。

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

  • 如果要重载 B 为类成员函数,使之能够实现表达式 oprd1 B oprd2,其中 oprd1 为A 类对象,则 B 应被重载为 A 类的成员函数,形参类型应该是 oprd2 所属的类型。
  • 经重载后,表达式 oprd1 B oprd2 相当于 oprd1.operator B(oprd2)
#include <iostream>
#include <cstdlib>
#include "Array.h"
using namespace std;

class Complex
{
	private:
		double real, img;
	public:
		Complex(double r=0, double i=0):real(r), img(i){}
		Complex operator + (const Complex &c2) const;
		Complex operator - (const Complex &c2) const;
		void display() const;
};

Complex Complex::operator + (const Complex &c2) const
{
	return Complex(real + c2.real, img + c2.img);
}

Complex Complex::operator - (const Complex &c2) const
{
	return Complex(real - c2.real, img - c2.img);
}

void Complex::display() const
{
	cout<<'('<<real<<", "<<img << ')'<<endl;
}

int main() {
	Complex c1(5, 4), c2(2, 10), c3;
    cout << "c1 = "; c1.display();
    cout << "c2 = "; c2.display();
    c3 = c1 - c2;   //使用重载运算符完成复数减法
    cout << "c3 = c1 - c2 = "; c3.display();
    c3 = c1 + c2;   //使用重载运算符完成复数加法
    cout << "c3 = c1 + c2 = "; c3.display();
    return 0;
}

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

前置单目运算符重载规则

  • 如果要重载 U 为类成员函数,使之能够实现表达式 U oprd,其中 oprd 为A类对象,则 U 应被重载为 A 类的成员函数,无形参。
  • 经重载后,表达式 U oprd 相当于 oprd.operator U()

后置单目运算符 ++和--重载规则

  • 如果要重载 ++或--为类成员函数,使之能够实现表达式 oprd++ 或 oprd-- ,其中 oprd 为A类对象,则 ++或-- 应被重载为 A 类的成员函数,且具有一个 int 类型形参。
  • 经重载后,表达式 oprd++ 相当于 oprd.operator ++(0)
#include <iostream>
#include <cstdlib>
#include "Array.h"
using namespace std;

class Clock
{
	private:
		int hour, minute, second;
	public:
		Clock(int hour=0, int minute=0, int second=0);
		Clock& operator ++ ();
		Clock operator ++ (int);
		void showTime() const{
			cout << hour << ":" << minute << ":" << second << endl;
		}
};

Clock::Clock(int hour, int minute, int second)
{
	if (0 <= hour && hour < 24 && 0 <= minute && minute < 60
        && 0 <= second && second < 60)
		{
			this->hour = hour;
			this->minute = minute;
			this->second = second;
		}
	else{cout << "Time error" << endl;}
}

Clock& Clock::operator ++ ()
{
	++second;
	if (second >= 60) {
        second -= 60;  minute++;
        if (minute >= 60) {
          minute -= 60; hour = (hour + 1) % 24;
        }
	}
	return *this;
}

Clock Clock::operator ++ (int)
{
	Clock old = *this;
	++(*this);
	return old;
}

int main() {
    Clock myClock(23, 59, 59);
    cout << "First time output: ";
    myClock.showTime();
    cout << "Show myClock++:    ";
    (myClock++).showTime();
    cout << "Show ++myClock:    ";
    (++myClock).showTime();
    return 0;
}

运算符重载为非成员函数

有些运算符不能重载为成员函数,例如二元运算符的左操作数不是对象,或者是不能由我们重载运算符的对象,这是需要重载为非成员函数。

  • 函数的形参代表依自左至右次序排列的各操作数。
  • 重载为非成员函数时,参数个数=原操作数个数(后置++、--除外)
  • 至少应该有一个自定义类型的参数。
  • 后置单目运算符 ++和--的重载函数,形参列表中要增加一个int,但不必写形参名。
  • 如果在运算符的重载函数中需要操作某类对象的私有成员,可以将此函数声明为该类的友元
  • 将<<(双目)重载为非成员函数,并将其声明为复数类的友元,它的左操作数是std::ostream引用,右操作数为复数类的常引用,返回std::ostream引用,用以支持下面形式的输出 :cout << a << b;
#include <iostream>
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<<(ostream &out, const Complex &c);
private:    
	double real;  //复数实部
	double imag;  //复数虚部
};

Complex operator+(const Complex &c1, const Complex &c2){
	return Complex(c1.real+c2.real, c1.imag+c2.imag); 
}
Complex operator-(const Complex &c1, const Complex &c2){
	return Complex(c1.real-c2.real, c1.imag-c2.imag); 
}

ostream & operator<<(ostream &out, const Complex &c){
	out << "(" << c.real << ", " << c.imag << ")";
	return out;
}

int main() {    
	Complex c1(5, 4), c2(2, 10), c3;    
	cout << "c1 = " << c1 << endl;
	cout << "c2 = " << c2 << endl;
	c3 = c1 - c2;   //使用重载运算符完成复数减法
	cout << "c3 = c1 - c2 = " << c3 << endl;
	c3 = c1 + c2;   //使用重载运算符完成复数加法
	cout << "c3 = c1 + c2 = " << c3 << endl;
	return 0;
}

虚函数

virtual关键字:进行动态绑定,不在编译期确定,而在执行的时候确定

virtual修饰的函数必须写在类外,不能写在类内,这成了内联函数,相矛盾

#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;
}

虚函数如何实现的?

  • 虚表

    • 每个多态类有一个虚表(virtual table)
    • 虚表中有当前类的各个虚函数的入口地址
    • 每个对象有一个指向当前类的虚表的指针(虚指针vptr)
  • 动态绑定的实现

    • 构造函数中为对象的虚指针赋值
    • 通过多态类型的指针或引用调用成员函数时,通过虚指针找到虚表,进而找到所调用的虚函数的入口地址
    • 通过该入口地址调用虚函数

8-1.png

抽象类

纯虚函数

  • 纯虚函数是一个在基类中声明的虚函数,它在该基类中没有定义具体的操作内容,要求各派生类根据实际需要定义自己的版本,纯虚函数的声明格式为:

    virtual 函数类型 函数名(参数表) = 0;

  • 带有纯虚函数的类称为抽象类

抽象类

  • 带有纯虚函数的类称为抽象类:

    virtual 类型 函数名(参数表)=0;

  • 只能作为基类使用,不能实例化对象

#include <iostream>
using namespace std;

class Base1 { 
public:
    virtual void display() const = 0;   //纯虚函数
};

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() {    
    Base2 base2;    
    Derived derived;    
    fun(&base2);    
    fun(&derived);  
    return 0;
}

override与final

override

猜你喜欢

转载自www.cnblogs.com/huanxifan/p/13380676.html
今日推荐