C++基础——多态

文章目录

  • 1 概述
  • 2 多态基本概念
  • 3 多态的使用
  • 4 纯虚函数和抽象类
  • 5 虚析构和纯虚析构

1 概述

多态是面向对象的三大特性之一,说的是同一个事物有不同的行为。
多态可分为:

  • 静态多态:函数重载和运算符重载
  • 动态多态:派生类和虚函数实现
    静态多态和动态多态的区别:
  • 静态多态:函数地址早期绑定 - 编译阶段确定函数地址
  • 动态多态:函数地址晚期绑定 - 运行阶段确定函数地址

2 多态基本概念

#include 

using namespace std;

class Father {
public:
    virtual void func() {
        cout << "father func" << endl;
    }
    //void func() {
    //    cout << "father func" << endl;
    //}
};

class Son : public Father {
public:
    void func() {
        cout << "son func" << endl;
    }
};

void test(Father &father) {
    father.func();
}

int main() {
    Father father;
    father.func();
    Son son;
    son.func();
    test(father);
    test(son);
    return 0;
}

输出

未使用virtual
father func
son func
father func
father func
使用virtual
father func
son func
father func
son func

使用自己的对象调用方法,则是和继承里面的处理相同。如果存在同名函数,子类直接调用为子类的函数,使用作用域限定符调用父类的函数。
如果没有virtual修饰,即使有父类引用指向子类对象,调用的也是父类的同名函数,而不会体现出多态行为。
而将父类的函数标记为virtual之后,就能使继承中存在多态关系,多态需满足条件:

  • 有继承关系
  • 子类重写父类中的虚函数
    多态使用条件:
    父类指针指向子类对象
    多态最常用的场景就是用父类的引用作为参数,传入不同的子类对象,能够实现不同的行为。

3 多态的使用

使用多态实现一个计算器类
普通实现:

#include 

using namespace std;

class Calculator {
public:
    int getResult(string oper) {
        if (oper == "+") {
            return m_Num1 + m_Num2;
        } else if (oper == "-") {
            return m_Num1 - m_Num2;
        } else if (oper == "*") {
            return m_Num1 * m_Num2;
        }
        //如果要提供新的运算,需要修改源码
    }

public:
    int m_Num1;
    int m_Num2;
};

void test01() {
    Calculator c;
    c.m_Num1 = 10;
    c.m_Num2 = 10;
    cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.getResult("+") << endl;

    cout << c.m_Num1 << " - " << c.m_Num2 << " = " << c.getResult("-") << endl;

    cout << c.m_Num1 << " * " << c.m_Num2 << " = " << c.getResult("*") << endl;
}

int main() {
    test01();
    return 0;
}

普通实现,通过判断来实现,如果需要新增算法,则需要改动类,对于类的封装性和扩展性都不好。
如果有了多态,可以这样实现:

#include 

using namespace std;

class AbstractCalculator {
public:
    virtual int getResult() {
        return 0;
    }

    int m_num1;
    int m_num2;
};

class AddCalculator : public AbstractCalculator {
public:
    int getResult() override {
        return m_num1 + m_num2;
    }
};

class SubCalculator : public AbstractCalculator {
    int getResult() override {
        return m_num1 - m_num2;
    }
};

class MulCalculator : public AbstractCalculator {
    int getResult() override {
        return m_num1 * m_num2;
    }
};

void test() {
    AbstractCalculator *abc = new AddCalculator;
    abc->m_num1 = 10;
    abc->m_num2 = 10;
    cout << abc->m_num1 << " + " << abc->m_num2 << " = " << abc->getResult() << endl;
    delete abc;

    abc = new SubCalculator;
    abc->m_num1 = 10;
    abc->m_num2 = 10;
    cout << abc->m_num1 << " - " << abc->m_num2 << " = " << abc->getResult() << endl;
    delete abc;

    abc = new MulCalculator;
    abc->m_num1 = 10;
    abc->m_num2 = 10;
    cout << abc->m_num1 << " * " << abc->m_num2 << " = " << abc->getResult() << endl;
    delete abc;
}

int main() {
    test();
    return 0;
}

通过继承和多态来实现,封装性和扩展性都要更强一些。

4 纯虚函数和抽象类

在多态中,通常父类中的虚函数没有实现,提供给子类重写,所以可以设置成纯虚函数
当类中有纯虚函数,这个类称为抽象类
抽象类的特点:

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也是抽象类
#include 

using namespace std;

class Father {
public:
    virtual void func() = 0;
};

class Son : public Father {
public:
    virtual void func() {
        cout << "Son func" << endl;
    }
};

void test() {
    // Father father;
    Father *father;
    father = new Son;
    father->func();
    delete father;
}

int main() {
    test();
    return 0;
}

输出

Son func

5 虚析构和纯虚析构

多态使用时,如果子类有属性开辟到堆区,那么父类指针释放的时候无法调用到子类的析构函数

#include 

using namespace std;

class Father {
public:
    virtual void func() = 0;
};

class Son : public Father {
public:
    ~Son() {
        cout << "Son deconstructor" << endl;
    }

    virtual void func() {
        cout << "Son func" << endl;
    }
};

void test() {
    Father *father;
    father = new Son;
    father->func();
    delete father;
}

int main() {
    test();
    return 0;
}

输出:

Son func

没有子类析构函数的打印
对于此问题,可以将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:

  • 可以解决父类指针释放子类对象
  • 都需要有具体的函数实现

虚析构和纯虚析构区别:

  • 如果是纯虚析构,该类属于抽象类,无法实例化对象
#include 

using namespace std;

class Father {
public:
    virtual void func() = 0;
    virtual ~Father() {
        cout << "Father deconstructor" << endl;
    }
    // virtual ~Father() = 0;
};

// Father::~Father() {
//     cout << "Father deconstructor" << endl;
// }

class Son : public Father {
public:
    ~Son() {
        cout << "Son deconstructor" << endl;
    }

    virtual void func() {
        cout << "Son func" << endl;
    }
};

void test() {
    Father *father;
    father = new Son;
    father->func();
    delete father;
}

int main() {
    test();
    return 0;
}

输出

Son func
Son deconstructor
Father deconstructor

此时子类析构函数被调用,可以在子类析构中进行动态内存释放。

  • 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
  • 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
  • 拥有纯虚析构函数的类也属于抽象类

你可能感兴趣的:(C++语言,c++,java,jvm)