PoEdu培训 C++班 第十五课 继承(2)
文章类别: 培训笔记 0 评论

PoEdu培训 C++班 第十五课 继承(2)

文章类别: 培训笔记 0 评论

继承(2)

为什么要有继承

代码复用

代码复用的方式

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

// 员工类
class Employee
{
public:
    Employee(const string& name, const int lev, const int salapyBase = 3000)
        :name_(name), lev_(lev), salapyBase_(salapyBase)
    {
    }

    int Salary()
    {
        // 基本工资 * 等级数
        return salapyBase_ * lev_;
    }
    int Salary(int addi)
    {
        // 基本工资 * 等级数
        return salapyBase_ * lev_ + addi;
    }
    int salapyBase_;
protected:
    string name_;
    int no_;
    int lev_;
};

// 经理类
class Manager : public Employee
{
public:
    Manager(const string& name, const int lev, const int salapyBase = 5000)
        :Employee(name, lev),
        salapyBase_(salapyBase),
        emps_(nullptr)
    {
    }

    // 经理的工资不一样
    // 函数重定义
    int Salary(double mutiple)
    {
        // 基本工资 * 等级数
        return salapyBase_ * (lev_ * mutiple);
    }
    int salapyBase_;
protected:
    Employee* emps_;
    // 基类有, 派生类又定义了一个, 我们叫做重定义
}

int main()
{
    Employee zs("张三", 10);
    Manager ls("李四", 10);
    cout << zs.Salary() << endl;
    cout << ls.Salary() << endl;

    cout << ls.salapyBase_ << endl;
    cout << ls.Employee::salapyBase_ << endl;

    return 0;
}

数据(成员变量)的重定义/隐藏它并非覆盖, 而是都存在

当Salary在Manager没有时,
调用的时候是调用的 ls.Employee::Salary();

但是, Salary()中调用的 salapyBase_ 是谁的呢?
答案是 Employee 的, 因为基类中是存在该变量的.

数据(成员变量)的重定义是有问题的做法!

派生类的函数名和基类相同时, 该函数被派生类重定义/隐藏

以Salary()为例, 基类和派生类的参数并不相同, 为什么是重定义而不是重载?
overload // 重载 相同作用域中才是重载
overwrite // 重定义, 隐藏 函数名相同就构成重定义
override // 覆盖 覆盖的是虚函数

因为他们不是同一作用域, 所以不是重载.

当派生类重写了基类的方法 Salary() 时, 在派生类中,
直接访问 Salary() 是访问不到的, 因为被重写后, 父类的多态重载会被隐藏.
默认会直接调用 Manager 类中的函数.
但是, 可以通过 ls.Employee::Salary() 来调用.

无法被继承的函数

函数调用时转换到基类

class A
{

};

class B : public A
{
public:
    int iB;
}

int main()
{
    B b;
    A a;

    A* pa = new A;
    B* pb = new B;

    pa = pb;    // 派生类向基类转换, OK
                // 会进行对象切割, 丢失特性.
    pa->iB;     // 无法访问, 已丢失
    pb = pa;    // 非法的  基类无法向派生类转换

    a = b;  // 安全转换, OK, VS会提示 你已丢失X个特性
    b = a;  // 非法

    return;
}

当派生类以public进行继承的时候, 可以进行转换

如果是 private 或者 protected 继承, 2者无法进行转换.
如果你认为是安全的, 可以使用 reinterpret_cast 强制转换

虚继承

在出现菱形继承的时候, 会产生一个虚基类.

菱形继承示意图

             /---------------\
             |               |
             | 家具类(虚基类) |
             |               |
             \---------------/
                     |
                     |
           /--------------------\
           |                    |
           |                    |
    /------------\      /--------------\
    |            |      |              |
    | 床(虚继承)  |      | 沙发(虚继承)  |
    |            |      |              |
    \------------/      \--------------/
           |                    |
           |                    |
           \--------------------/
                     |
                     |
             /---------------\
             |               |
             | 沙发床(派生类) |
             |               |
             \---------------/

虚基类的构造方法由最远的派生类来进行调用.

如有错误,请提出指正!谢谢.

回复