• 【C++】类-多态


    类-多态

    1. 基本概念

    多态性:

    • 操作接口具有表现多种形态的能力,能根据操作环境的不同采用不同的处理方式。
    • 一组具有相同基本语义的方法能在同一接口下为不同的对象服务。

    实现方式:

    绑定机制 绑定是将一个标识符名和一个存储地址联系在一起的过程。例如:虚函数的实现对应着虚表,每一个派生类都包含了一个指向虚表的指针,运行时根据对象的指针找到虚表指针,然后取出对应的函数

    • 静态绑定:编译阶段完成
    • 动态绑定:运行时完成

    分类:

    • 静态多态性:运算符重载
    • 动态多态性:虚函数

    2. 运算符重载

    2.1 重载为类的成员函数

    函数类型 operator 运算符(形参)
    {
    ......
    }
    参数个数=原操作数个数-1 (后置++、--除外)
    

    eg1:复数重载加法

    class Complex {
    public:
    	Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) { }
    	//运算符+重载成员函数
    	Complex operator + (const Complex& c2) const;
    	//运算符-重载成员函数
    	Complex operator - (const Complex& c2) const;
    	void display() const; //输出复数
    private:
    	double real; //复数实部
    	double imag; //复数虚部
    };
    Complex Complex::operator+(const Complex& c2) const {
    	//创建一个临时无名对象作为返回值
    	return Complex(real + c2.real, imag + c2.imag);
    }
    Complex Complex::operator-(const Complex& c2) const {
    	//创建一个临时无名对象作为返回值
    	return Complex(real - c2.real, imag - c2.imag);
    }void Complex::display() const {
    	cout << "(" << real << ")+(" << imag << ")j" << endl;
    }
    

    eg2:时钟类重载自增。后置自增需要传递一个参数

    class Clock {//时钟类定义
    public:
    	Clock(int hour = 0, int minute = 0, int second = 0);
    	void showTime() const;
    	//前置单目运算符重载
    	Clock& operator ++ ();
    	//后置单目运算符重载
    	Clock operator ++ (int);
    private:
    	int hour, minute, second;
    };
    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;
    }
    void Clock::showTime() const { //显示时间
    	cout << hour << ":" << minute << ":" << second << 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;
    }
    

    2.2 重载为非成员函数

    如果数据是类的private成员,需要将函数声明为友元函数

    eg:复数重载加减法和输出流运算符

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

    3. 虚函数

    • 通过virtual关键字实现
    • 虚函数必须是非静态成员函数,也不能是内联函数(编一阶段必须定下来的)
    • 构造函数不能是虚函数,析构函数可以

    eg1:

    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 override;
    };
    void Derived::display() const {
    	cout << "Derived::display()" << endl;
    }
    void fun(Base1* ptr) {
    	ptr->display();
    }
    

    调用函数fun()时,能够根据指针的实际类型调用正确的函数

    eg2:虚析构函数。使用了new运算符创建对象,然后要用对象指针释放空间

    #include <iostream>
    using namespace std; 
    class Base {
    public:
    	virtual ~Base(); //不是虚函数
    };
    Base::~Base() {
    	cout << "Base destructor" << endl;
    }
    class Derived : public Base {
    public:
    	virtual ~Derived(); //不是虚函数
    };
    Derived::~Derived() {
    	cout << "Derived destructor" << endl;
    }
    void release(Base* p) {
    	delete p;
    }
    int main() {
    	Derived* pObj = new Derived();
    	release(pObj);
    	return 0;
    }
    

    基类和子类的析构函数都会被调用。如果析构函数非虚,那么只会调用基类的析构函数,子类中新增加的成员可能不会被释放,造成内存泄漏

    4. 抽象类

    定义:带纯虚函数的类是抽象类

    纯虚函数:没有函数体的虚函数 virtual 函数类型 函数名(参数表) = 0;

    抽象类作用

    • 抽象类为抽象和设计的目的而声明
    • 将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。
    • 对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。

    注意

    • 抽象类只能作为基类来使用。
    • 不能定义抽象类的对象。

    5. overridefinal

    • override显式指明该函数是虚函数,编译器检查在基类中如果没有对应的函数,会报错
    • final用来避免类被继承,或是基类的函数被改写
  • 相关阅读:
    第五章 数据的共享与保护
    实验6
    实验5
    实验4 类与对象2)
    实验三 类与对象
    实验2
    2018—3-21第二章程序例题(2)
    第二章思维导图
    2018—3-18C++第二章程序例题
    汇编实验九
  • 原文地址:https://www.cnblogs.com/vinnson/p/13451296.html
Copyright © 2020-2023  润新知