//
// main.cpp
// _day6
//
// Created by AchesonD16 贪玩巴斯 on 2021/4/23.
//
//继承是面向对象三大特性之一
//
//有些类与类之间存在特殊的关系,例如:
//我们发现,定义这些类时,下一级别的成员除了拥有上一级的共性,并且还拥有自己的特性
//这个时候我们可以考虑利用继承的技术,减少重复代码
//例如我们看到的很多网站中,都有公共的头部,公共的底部,甚至公共的左侧列表,只有中心内容不同
//接下来我们分别利用普通写法和继承的写法来实现网页中的内容,看一下继承存在的意义以及好处
#include
using namespace std;
/*
class java
{
public:
void header()
{
cout << "首页、公开课、登录、注册...(公共头部)" << endl;
}
void footer()
{
cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
}
void left()
{
cout << "Java,Python,c++...(公共分类列表)" << endl;
}
void content()
{
cout << "JAVA学科视频" << endl;
}
};
//Python页面
class Python
{
public:
void header()
{
cout << "首页、公开课、登录、注册...(公共头部)" << endl;
}
void footer()
{
cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
}
void left()
{
cout << "Java,Python,c++...(公共分类列表)" << endl;
}
void content()
{
cout << "Python学科视频" << endl;
}
};
//c++页面
class Cpp
{
public:
void header()
{
cout << "首页、公开课、登录、注册...(公共头部)" << endl;
}
void footer()
{
cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
}
void left()
{
cout << "Java,Python,c++...(公共分类列表)" << endl;
}
void content()
{
cout << "c++学科视频" << endl;
}
};
void test1()
{
//Java页面
cout << "Java下载视频页面如下:" << endl;
java ja;
ja.header();
ja.footer();
ja.left();
ja.content();
cout << "---------------------" << endl;
//Python页面
cout << "Python下载视频页面如下:" << endl;
Python py;
py.header();
py.footer();
py.left();
py.content();
cout << "---------------------" << endl;
//c++页面
cout << "c++下载视频页面如下:" << endl;
Cpp c;
c.header();
c.footer();
c.left();
c.content();
cout << "---------------------" << endl;
}
int main()
{
test1();
system("pause");
return 0;
}
*/
/*
#include
using namespace std;
//公共页面
class BasePage
{
public:
void header()
{
cout << "首页、公开课、登录、注册...(公共头部)" << endl;
}
void footer()
{
cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
}
void left()
{
cout << "Java,Python,c++...(公共分类列表)" << endl;
}
};
//Java页面 //固定格式 class 子类(派生类) : 继承方式 父类(基类)
class Java : public BasePage //继承了父类的所有属性行为。
{
public: //同时具有自己的个性——自己的行为和属性
void content()
{
cout << "JAVA学科视频" << endl;
}
};
//Python页面
class Python : public BasePage
{
public:
void content()
{
cout << "Python学科视频" << endl;
}
};
class Cpp : public BasePage
{
public:
void content()
{
cout << "c++学科视频" << endl;
}
};
void test1()
{
//Java页面
cout << "Java下载视频页面如下:" << endl;
Java ja;
ja.header();
ja.footer();
ja.left();
ja.content();
cout << "------------------" << endl;
//Python页面
cout << "Python下载视频页面如下: " << endl;
Python py;
py.header();
py.footer();
py.left();
py.content();
cout << "--------------------" << endl;
//C++页面
cout << "C++下载视频页面如下: " << endl;
Cpp cp;
cp.header();
cp.footer();
cp.left();
cp.content();
}
int main()
{
test1();
system("pause");
return 0;
}
继承的好处:可以减少重复的代码
class A : public B
{};
A 类称为子类 或 派生类
B 类称为父类 或 基类
派生类中的成员,包含两大部分:
一类是从基类继承过来的,一类是自己增加的成员。
从基类继承过来的 表现其共性,而新增的成员 体现了其个性。
*/
/*
//继承方式
//继承的语法:
class 子类 :继承方式 父类
//
//继承方式一共有三种:
//公共继承
//保护继承
//私有继承
//
#include
using namespace std;
class Base1
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
//公共继承 public
class Son1 : public Base1
{
public:
void func()
{
m_A = 10; //可访问 public权限
m_B = 12; //可访问 protected权限
//m_C = 4; //不可访问 为父类的私有属性
}
};
void myClass(int a)
{
Son1 s1;
s1.m_A = a; //在类外只能调用公共类
cout << s1.m_A << endl;
}
//保护继承 protected
class Base2
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son2 : protected Base2
{
public:
void func()
{
m_A = 5; //可访问 protected权限
m_B = 55; //可访问 protected权限
//m_C = 23; //不可访问,其为父类的私有属性
}
};
void myClass2()
{
Son2 s2;
s2.func();
//s2.m_A; 是不可以访问的,因为其继承过来为 protected权限
}
//私有继承
class Base3
{
public:
int m_A;
protected:
int m_B;;
private:
int m_C;
};
class Son3:private Base3
{
public:
void func()
{
m_A = 10; //可访问 private权限
m_B = 23; //可访问 private权限
//m_C; 不可以访问
}
};
class GrandSon3:public Son3
{
public:
void func()
{
// 验证Son3的继承为私有继承,从Base3继承过来的皆为私有属性
//m_A = m_B = 2; //不可以
}
};
int main()
{
myClass(2);
myClass2(); //什么都不显示,因为是protected权限,出了类无法访问
system("pause");
return 0;
}
*/
// 继承中的对象模型
// 从父类继承过来的成员,哪些属于子类对象中的?
#include
using namespace std;
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C; //私有成员被隐藏了,但是还是会继承下去
};
//公共继承
class Son:public Base
{
public:
int m_D;
};
void test1()
{
cout << "sizeof Son = " << sizeof(Son) << endl;
}
int main()
{
test1();
system("pause");
return 0;
}
结果:
sizeof Son = 16
结论:
父类中私有成员也是被子类继承下去了, 只是由编译器给隐藏后访问不到
// 使用 程序员命令管理符来查看
打开工具窗口后,定位到当前CPP文件的盘符
然后输入: cl /d1 reportSingleClassLayout查看的类名 所属文件名
效果如下图:
*/
/*
//继承中构造和析构顺序
//子类继承父类后,当创建子类对象,也会调用父类的构造函数
//问题:那么父类和子类的构造和析构顺序是谁先谁后呢?
#include
using namespace std;
class Base
{
public:
Base()
{
cout << "Base构造函数!" << endl;
}
~Base()
{
cout << "Base析构函数!" << endl;
}
};
class Son:public Base
{
public:
Son()
{
cout << "Son构造函数!" << endl;
}
~Son()
{
cout << "Son析构函数!" << endl;
}
};
void test1()
{
//继承中 先调用父类构造函数,再调用子类构造函数, 析构顺序与构造相反,(栈先进后出) —— 先有爸爸后有儿子
Son s;
}
int main()
{
test1();
system("pause");
return 0;
}
结果:
Base构造函数!
Son构造函数!
Son析构函数!
Base析构函数!
总结:
继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
*/
/*
// 继承同名成员处理方式
// 访问子类同名成员 直接访问即可
// 访问父类同名成员 需要加作用域
#include
using namespace std;
class Base //创建基类、父类
{
public:
Base()
{
m_A = 100; //创建同名成员
}
void func() //同名函数
{
cout << "Base - func()调用" << endl;
}
void func(int a) //函数重载
{
cout << "Base -func(int a)调用" << endl;
}
public:
int m_A;
};
class Son:public Base //创建子类,继承父类
{
public:
Son()
{
m_A = 200; // 同名
}
//当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
//如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域
void func() // 同名
{
cout << "Son - func()调用" << endl;
}
public:
int m_A;
};
void test1()
{
Son s;
cout << "Son下的m_A = " << s.m_A << endl;
cout << "Base下的m_A = " << s.Base::m_A << endl; // 加作用域可以访问
s.func();
s.Base::func(); // 加 父类作用域
s.Base::func(10); // 加 作用域
}
int main()
{
test1();
system("pause");
return 0;
}
结果:
Son下的m_A = 200
Base下的m_A = 100
Son - func()调用
Base - func()调用
Base -func(int a)调用
总结:
1、子类对象可以直接访问到子类中同名的成员。
2、子类对象加作用域可以访问到父类同名成员。
3、当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域才可以访问到父类中同名函数
*/
/*
// 继承同名静态成员处理方式
// 静态成员和非静态成员出现同名,处理方式一致
// 1、访问子类同名成员 直接访问即可
// 2、访问父类同名成员 需要加作用域
#include
using namespace std;
class Base
{
public:
static void func() // 构造静态成员函数
{
cout << "Base - static void func()" << endl;
}
static void func(int a)
{
cout << "Base - static void func(int a)" << endl;
}
static int m_A; //静态成员变量 , 类内定义,类外初始化
};
int Base::m_A = 100;
class Son : public Base // 构造派生类,子类
{
public:
static void func() // 同名
{
cout << "Son - static void func()" << endl;
}
static int m_A; // 同名
};
int Son::m_A = 200; // 记得加作用域在中间
//同名成员属性
void test1()
{
// 通过对象访问
cout << "通过对象访问:" << endl;
Son s;
cout << "Son 下 m_A = " << s.m_A << endl;
cout << "Base下 m_A = " << s.Base::m_A << endl; // 加作用域访问父类中的同名静态成员变量
// 通过类名访问
cout << "通过类名访问: " << endl;
cout << "Son 下 m_A = " << Son::m_A << endl;
cout << "Base下 m_A = " << Son::Base::m_A << endl;
}
//同名成员函数
void test2()
{
//通过对象访问
cout << "通过对象访问:" << endl;
Son s;
s.func();
s.Base::func(); // 加作用域以访问父类中同名静态成员函数
cout << "通过类名访问:" << endl;
Son::func();
Son::Base::func();
//出现同名,子类会隐藏父类中所有同名成员函数,需要加作用域访问
Son::Base::func(100);
}
int main()
{
test1();
test2();
system("pause");
return 0 ;
}
结果:
通过对象访问:
Son 下 m_A = 200
Base下 m_A = 100
通过类名访问:
Son 下 m_A = 200
Base下 m_A = 100
通过对象访问:
Son - static void func()
Base - static void func()
通过类名访问:
Son - static void func()
Base - static void func()
Base - static void func(int a)
总结:
同名静态成员 处理方式和 非静态处理方式一样,只不过有两种访问的方式(通过对象 和 通过类名)
*/
/*
// 多继承语法
// c++允许一个类继承多个父类
// 语法:class 子类 :继承方式 父类1, 继承方式 父类2 ... {};
// 多继承可能会引发父类中有同名成员出现,需要加作用域区分
// 注意: c++实际开发中不建议用多继承
#include
using namespace std;
class Base1
{
public:
Base1()
{
m_A = 100;
}
public:
int m_A;
};
class Base2
{
public:
Base2()
{
m_A = 200; // 如果同名会 出现不明确
}
public:
int m_A;
};
// 多继承语法: class 子类: 继承方式 父类1, 继承方式2 父类2, ...{};
class Son : public Base1, public Base2
{
public:
Son()
{
m_C = 300;
m_D = 400;
}
public:
int m_C;
int m_D;
};
// 多继承容易产生成员同名的情况
// 通过使用类名作用域可以区分调用哪一个基类的成员
void test1()
{
Son s;
cout << "sizeof Son = " << sizeof(s) << endl;
cout << s.Base1::m_A << endl;
cout << s.Base2::m_A << endl;
}
int main()
{
test1();
system("pause");
return 0;
}
结果:
sizeof Son = 16
100
200
总结:
多继承中如果多个父类中出现了同名情况,子类使用的时候要加作用域
*/
// 菱形继承
/*
菱形继承的概念:
两个派生类继承同一个基类
又有某个类同时继承着这两个派生类
构成菱形◇
这种继承被称为 菱形继承, 或者 钻石继承
典型的菱形继承案例:
菱形继承问题:
羊继承了动物,驼同样继承了动物的数据,草泥马同时继承了驼类,羊类,那么当草泥马使用当中的数据时,就会产生二义性
草泥马继承自动物的数据继承了两份,其实我们应该很清楚,这份数据我们只需要一份就可以了。
#include
using namespace std;
class Animal
{
public:
int m_Age;
};
//解决继承两份数据的方法 : 继承前加 virtual 关键字后, 变为虚继承
//此时公共的最大的父类Animal称为 虚基类
class Sheep : virtual public Animal
{};
class Tuo : virtual public Animal
{};
class SheepTuo : public Sheep, public Tuo
{};
void test1()
{
SheepTuo st; // 创建羊驼的对象
st.Sheep::m_Age = 100; //访问的是羊作用域下继承的父类的m_Age
st.Tuo::m_Age = 200; //访问的是驼作用域下继承的父类的m_Age
cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;
cout << "st.m_Age = " << st.m_Age << endl;
}
int main()
{
test1();
system("pause");
return 0;
}
结果:
st.Sheep::m_Age = 200
st.Tuo::m_Age = 200
st.m_Age = 200
总结:
使用了虚继承,那么最后赋值的为最终的值的结果
菱形继承带来的问题主要是子类继承两份相同的数据,导致了资源浪费以及毫无意义
利用虚继承可以解决菱形继承问题!!
*/