127讲 继承的语法、继承方式
继承的语法
#include <iostream>
#include "string"
using namespace std;
class base_giegie {
public:
void ikun() {
cout << "小黑子,又在黑人家giegie !!! " << endl;
}
void smallBlack() {
cout << "食不食香精煎鱼?" << endl;
}
void protectMyGiegie() {
cout << "人家哥哥下的蛋你有本事别吃!!!" << endl;
}
};
class fengRenJi : public base_giegie {
public:
void jianYu() {
cout << "小黑子食不食香菜凤仁鸡?" << endl;
}
};
class prison : public base_giegie {
public:
void laoFan() {
cout << "食不食香翅捞饭?" << endl;
}
};
void main() {
fengRenJi giegie;
giegie.jianYu();
giegie.ikun();
giegie.smallBlack();
giegie.protectMyGiegie();
cout << "================================" << endl;
prison jianyu;
jianyu.laoFan();
jianyu.ikun();
jianyu.smallBlack();
jianyu.protectMyGiegie();
}
继承方式
注意: 成员继承了父类的私有成员,隐藏了虽然不能直接访问,但是依旧会继承下去。
这么继承下来的作用是:如果父类有的函数需要访问父类的私有成员,那么继承下来就是为了让他康康!!!参考知乎文章如下
继承中的对象模型
补充一个知识点:
在类未声明成员的时候它占用的字节是 1,因为C++ 中每一个类中都要分配一个内存地址
但是,如果类有一个成员或者多个成员,则占用空间按照实际的来。比如有一个int 类型的成员,则这个类它就占用4字节
- 使用开发工具命令提示工具,查找类的继承对象模型
- 跳转盘符,
- cd 进入路径
- dir 查看当前文件信息,然后再输入下面的信息。
命令: E:\learnC++\继承与多态\继承与多态>cl /d1 reportSingleClassLayoutSheepTuo "多继承语法.cpp"
#include<iostream>
#include"string"
using namespace std;
class Base1 {
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son : public Base1 {
public:
int m_D;
};
void test() {
Son son;
cout << "sizeof(son) = " << sizeof(Son) << endl; //输出16,父类中所有的非静态成员属性都会继承下来,只是private 权限的成员被隐藏了。
}
void main() {
test();
}
calculate:父类中私有成员也是被子类继承下去了,只是编译器给隐藏后访问不到
继承中构造和析构顺序
子类继承父类之后,当创建子类对象,也会调用父类的构造函数
question:父类和子类的构造和析构的先后顺序是?
answer: 继承中,先调用父类构造函数,再调用子类构造。析构的时候先析构子类,然后再析构父类。
我的理解是:
- 1.因为父类东西要传给子类,所以得先有父类。
2.子类先析构的原因是,如果父类先析构,那么子类的属性就会缺失,导致不可预见的错误,所以子类必须先析构,等子类属性消失后再析构父类。
继承中同名的成员处理方法
同名成员属性的访问方法。
同名成员函数的处理
#include <iostream>
#include "string"
using namespace std;
class Base {
public:
void func() {
cout << "父类 的func() 被调用!" << endl;
}
void func(int a) {
cout << "the \"func(int a)\" of class Base has been used" << endl;
}
};
class Son : public Base{
public:
void func() {
cout << "子类 的func() 被调用!!" << endl;
}
};
void test() {
Son mySon;
mySon.Base::func();
//mySon.func(100); //哪怕是父类有重载,子类没重载,虽然子类父类能够区分,但是父类的成员函数依旧被隐藏掉了,只能加作用域:: 来访问父类的成员函数!!!!
}
void main() {
test();
}
calculate:
- 子类对象可以直接访问到子类同名成员
- 子类对象加作用域可以访问到父类同名成员
- 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数。
继承下的同名静态成员的处理
回顾
- 静态成员类内声明,类外初始化。
- 在编译的时候就分配内存(不是分配计算机内存条物理意义上的内存,我猜是写进汇编语言,让程序运行的时候就给它分配内存)
- 静态成员函数只能访问静态成员。 我的理解: 因为它属于全局区,如果它有非静态成员,那么该成员的生命结束后销毁了,让静态函数怎么玩?。
- 两种访问方式:1.通过对象访问。2.通过类名访问
解释:
Son::Base::m_A
第一个:: 表示通过类名方式访问 第二个:: 代表访问父类作用域下的成员
同理,静态成员函数如果子类出现同名,则父类的静态成员函数也会被隐藏
同名静态成员处理方式和非静态处理方式一样,只不过有两种访问方式(通过对象 和 通过类名)
多继承语法
在C++中不建议使用多继承。使用的时候容易冲突。因为项目往往不是一个人写的。 还是 JAVA 人性化
- C++ 允许一个类继承多个类
语法: class 子类 : 继承方式 父类1 , 继承方式 父类2 ...
我的评价是,这是吕布行为。
//笑死了
class 丁原 {public: int m_A;};
class 董卓 {public: int m_A;};
class 王允 {public: int m_A;};
class 吕布 : public 丁原, public 董卓, public 王允 {
public:
void toBeMultiSon(){
cout << "爹!!!" << endl;
}
int m_A;
};
void main(){
吕布 lvbu;
//cout << lvbu.m_A; //这里会报错,因为吕布不知道要找哪一个爹,所以当父类中出现多个重名成员,需要加作用域::符号加以区分。
cout << lvbu.董卓::m_A;
}
calculate:多继承中父类中如果出现了同名情况,子类使用时要加作用域。
菱形继承
菱形继承概念:
- 两个派生类继承同一个基类
- 又有某个类同时继承这两个派生类
- 这种继承称为菱形继承
利用虚继承可以解决菱形继承所遇到的问题!!!
virtual 关键字
calculate:
- 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
- 利用虚继承可以解决菱形继承的问题。
#include <iostream>
#include "string"
using namespace std;
class Animal {
public:
int m_Age;
};
class Sheep : virtual public Animal {}; //继承时使用关键字,virtual
class Tuo : virtual public Animal {};
class SheepTuo : public Sheep, public Tuo {};
void test() {
SheepTuo st;
st.Tuo::m_Age = 100;
st.Sheep::m_Age = 200;
cout << st.Tuo::m_Age << endl;
cout << st.Sheep::m_Age << endl;
}
void main() {
test();
}
虚基类继承继承的不是数据,而是指针。vbptr ( virtual base pointer ) 虚基类指针