继承(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() 来调用.无法被继承的函数
- 构造函数
- 析构函数
- operator=
函数调用时转换到基类
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 强制转换
虚继承
在出现菱形继承的时候, 会产生一个虚基类.
菱形继承示意图
/---------------\
| |
| 家具类(虚基类) |
| |
\---------------/
|
|
/--------------------\
| |
| |
/------------\ /--------------\
| | | |
| 床(虚继承) | | 沙发(虚继承) |
| | | |
\------------/ \--------------/
| |
| |
\--------------------/
|
|
/---------------\
| |
| 沙发床(派生类) |
| |
\---------------/
虚基类的构造方法由最远的派生类来进行调用.
如有错误,请提出指正!谢谢.
本文由 花心胡萝卜 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: 2017-02-19 at 04:03 pm