一、基本语法
继承:面向对象的三大特性之一
使用例子模拟实现的方法来理解更加容易:
模拟一个学习网页的页面
一个网站有很多的网页,每个网页有相同的部分和不同的部分
各个网页相同的部分可以采用继承的方法来写,这样就避免了写重复的代码
首先来看看 不采用 继承 技术来写的代码-----超级菜鸟级别:
#include
using namespace std;
//逻辑上,模拟写一个网站
//网站有多个页面:
//页面一:C++ 页面
class Cpp {
public:
//页面的公共部分:
//页眉部分
void Header() {
cout << "首页 番剧 直播 游戏中心 会员购 漫画 赛事" << endl;
}
//底部部分
void Bottomer() {
cout << "评论 联系方式 投诉" << endl;
}
//左侧部分
void lefter() {
cout << "CPP Java Python" << endl;
}
public:
//CPP页面独有部分
void Viodeo() {
cout << "C++一天速成 C++实战项目" << endl;
}
};
//CPP页面的链接入口
void enterCPP() {
cout << "-----------------------CPP-------------------------" << endl;
Cpp c;
c.Bottomer();
c.Header();
c.lefter();
c.Viodeo();
cout << endl;
cout << endl;
}
//页面二:Java 页面
class Java {
public:
//页面的公共部分:
//页眉部分
void Header() {
cout << "首页 番剧 直播 游戏中心 会员购 漫画 赛事" << endl;
}
//底部部分
void Bottomer() {
cout << "评论 联系方式 投诉" << endl;
}
//左侧部分
void lefter() {
cout << "CPP Java Python" << endl;
}
public:
//CPP独有部分
void Viodeo() {
cout << "Java一天速成 Java实战项目" << endl;
}
};
//Java页面的链接入口
void enterJava() {
cout << "-----------------------Java-------------------------" << endl;
Java j;
j.Bottomer();
j.Header();
j.lefter();
j.Viodeo();
cout << endl;
cout << endl;
}
//页面三:Python 页面
class Python {
public:
//页面的公共部分:
//页眉部分
void Header() {
cout << "首页 番剧 直播 游戏中心 会员购 漫画 赛事" << endl;
}
//底部部分
void Bottomer() {
cout << "评论 联系方式 投诉" << endl;
}
//左侧部分
void lefter() {
cout << "CPP Java Python" << endl;
}
public:
//Python独有部分
void Viodeo() {
cout << "Python一天速成 Python实战项目" << endl;
}
};
//Python页面的链接入口
void enterPython() {
cout << "----------------------Python------------------------" << endl;
Python p;
p.Bottomer();
p.Header();
p.lefter();
p.Viodeo();
cout << endl;
cout << endl;
}
int main() {
//模拟点击 C++链接
enterCPP();
//模拟点击 Java链接
enterJava();
//模拟点击 Python链接
enterPython();
return 0;
}
运行结果:
继承的优点:减少重复代码
基本语法:
class A: public B
A 为子类或者称为派生类
B 为父类或者称为基类
public 继承方式(有很多种)
即:
class 子类:继承方式 基类
//采用继承的技术来写:
#include
using namespace std;
//公共页面:
class BasePage {
public:
//页面的公共部分:
//页眉部分
void Header() {
cout << "首页 番剧 直播 游戏中心 会员购 漫画 赛事" << endl;
}
//底部部分
void Bottomer() {
cout << "评论 联系方式 投诉" << endl;
}
//左侧部分
void lefter() {
cout << "CPP Java Python" << endl;
}
};
class CPP : public BasePage {
public:
//CPP独有部分
void Viodeo() {
cout << "C++一天速成 C++实战项目" << endl;
}
};
class Java : public BasePage {
public:
//Java独有部分
void Viodeo() {
cout << "Java一天速成 Java实战项目" << endl;
}
};
class Python : public BasePage {
public:
//Python独有部分
void Viodeo() {
cout << "Python一天速成 Python实战项目" << endl;
}
};
//CPP页面的链接入口
void enterCPP() {
cout << "-----------------------CPP-------------------------" << endl;
CPP c;
c.Bottomer();
c.Header();
c.lefter();
c.Viodeo();
cout << endl;
cout << endl;
}
//Java页面的链接入口
void enterJava() {
cout << "-----------------------Java-------------------------" << endl;
Java j;
j.Bottomer();
j.Header();
j.lefter();
j.Viodeo();
cout << endl;
cout << endl;
}
//Python页面的链接入口
void enterPython() {
cout << "----------------------Python------------------------" << endl;
Python p;
p.Bottomer();
p.Header();
p.lefter();
p.Viodeo();
cout << endl;
cout << endl;
}
int main() {
//模拟点击 C++链接
enterCPP();
//模拟点击 Java链接
enterJava();
//模拟点击 Python链接
enterPython();
return 0;
}
运行结果:
二、继承方式
三种继承方式:
1、公共继承
2、保护继承
3、私有继承
实际上对应的是类中的三种访问权限
//代码示例:
#include
using namespace std;
//1、公共继承示例:
//父类1:
class Base1 {
public:
int m_public_A;
protected:
int m_protected_A;
private:
int m_private_A;
};
//继承1
class son1:public Base1 {
public:
void func() {
m_public_A = 10;//(公共继承的情况下)父类中的公共权限,子类中依然为公共权限
m_protected_A = 10;//(公共继承的情况下)父类中的保护权限,子类中依然为保护权限
//m_private_A = 10;// err (公共继承的情况下)父类中的私有权,子类不可访问
}
};
//测试(对继承中的结论进行验证)
void test1() {
son1 s1;
s1.m_public_A = 10;//m_public_A 在父类子类中都是公共权限,类外可以访问
//s1.m_protected_A = 10;// err m_protected_A 在父类和子类中都是保护权限,类外不可以访问
}
//2、保护继承示例:
//父类2:
class Base2 {
public:
int m_public_A;
protected:
int m_protected_A;
private:
int m_private_A;
};
//继承2
class son2 :protected Base2 {
public:
void func() {
m_public_A = 10;//(保护继承的情况下)父类中的 公共权限,子类中变为 保护权限
m_protected_A = 10;//(保护继承的情况下)父类中的 保护权限,子类中依然为 保护权限
//m_private_A = 10;// err (保护继承的情况下)父类中的私有权,子类不可访问
}
};
//测试(对继承中的结论进行验证)
void test2() {
son2 s2;
//s2.m_public_A = 10;//err m_public_A 在子类中都是保护权限,类外不可以访问
//s2.m_protected_A = 10;// err m_protected_A 在父类和子类中都是保护权限,类外不可以访问
}
//3、私有继承示例:
//父类3:
class Base3 {
public:
int m_public_A;
protected:
int m_protected_A;
private:
int m_private_A;
};
//继承3
class son3 :private Base3 {
public:
void func() {
m_public_A = 10;//(私有继承的情况下)父类中的 公共权限,子类中变为 私有权限
m_protected_A = 10;//(私有继承的情况下)父类中的 保护权限,子类中变为 私有权限
//m_private_A = 10;// err (私有继承的情况下)父类中的私有权,子类不可访问
}
};
//测试(对继承中的结论进行验证)
void test3() {
son3 s3;
//s3.m_public_A = 10;//err m_public_A 在子类中都是私有权限,类外不可以访问
//s3.m_protected_A = 10;// err m_protected_A 在父类中是保护权限,
// 在子类中是私有权限,类外不可以访问
}
int main() {
test1();
test2();
test3();
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 test() {
//打印输出一下子类类型的大小:
cout << "size of son = " << sizeof(son) << endl;
//打印结果为 16 = 4 * 4
//即 4 个 int 型变量的大小
//注:子类会继承父类的私有权限下的变量,
// 但是编译器将它隐藏了,子类无法访问
}
int main() {
test();
return 0;
}
结果:
使用 vs 的工具 Developer command prompt 可以验证上述结论,这里不进行演示。
四、继承之中构造和析构的顺序:
在父类中:
先调用构造函数,
之后调用析构函数
在子类中:
先调用父类的构造函数
再调用子类的构造函数
再调用子类的析构函数
再调用子类的析构函数
代码演示:
#include
using namespace std;
//写一个父类:
class Base {
public:
Base() {
cout << "父类中 构造函数 的调用" << endl;
}
~Base() {
cout << "父类中 析构函数 的调用" << endl;
}
};
//采用继承写一个子类:
class son :public Base {
public:
son() {
cout << "子类中 构造函数 的调用" << endl;
}
~son() {
cout << "子类中 析构函数 的调用" << endl;
}
};
//测试案例:
void test01() {
cout << "--------------父类----------------" << endl;
Base b;
cout << endl;
}
void test02() {
cout << "--------------子类----------------" << endl;
son s;
cout << endl;
}
int main() {
test01();
test02();
return 0;
}
结果:
五、继承同名成员处理方式
问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?
访问子类同名成员 直接访问即可
访问父类同名成员 需要加作用域
代码示例:
#include
using namespace std;
//创建父类:
class Base {
public:
int m_A = 10;
public:
void func1() {
cout << "Base'func1()" << endl;
}
};
//创建一个子类
class son:public Base {
public:
int m_A = 100;
public:
void func1() {
cout << "son'func1()" << endl;
}
};
void test01() {
cout << "-----------直接访问子类------------" << endl;
//直接访问子类得到的是子类本身的变量和函数:
son s;
cout << "son'm_A = " << s.m_A << endl;//结果:100
s.func1();// 结果:"son'func1()"
}
void test02() {
cout << "----------通过子类访问父类-----------" << endl;
//要想访问子类继承到的父类的变量和函数,需要加一个 作用域
son s;
cout << "Base'm_A = " << s.Base::m_A << endl;//结果:100
s.Base::func1();//结果:"Base'func1()"
}
int main() {
test01();
test02();
return 0;
}
结果:
六、同名静态成员处理
同名静态成员的处理本质上和非静态同名成员的处理相同,
有所不同的仅仅是多了一种使用 类名 访问的技术
同名成员有同名成员变量和同名成员函数,两者处理方式相同
代码示例:
#include
using namespace std;
//写一个父类:
class Base {
public:
//静态变量:
//静态变量作为成员变量,类内声明,类外初始化
static int m_A;
public:
//静态成员函数:
static void func() {
cout << "\tBase'func()" << endl;
}
};
//初始化:
int Base::m_A = 10;
//写一个子类,继承上面的父类:
class son: public Base{
public:
//与父类同名的静态变量:
static int m_A;
public:
//静态成员函数:
static void func() {
cout << "\tson'func()" << endl;
}
};
//初始化:
int son::m_A = 20;
void test01() {
cout << "--------静态成员变量---------" << endl;
cout << endl;
//1、通过对象访问:
cout << "通过对象访问:" << endl;
son s;//创建一个对象
//与非静态同名成员变量的访问相同:
//子类自己的静态变量直接访问即可:
cout << "\tson'm_A = " << s.m_A << endl;// 结果:son'm_A = 20
//通过子类访问父类的静态成员变量需要加一个作用域:
cout << "\tBase'm_A = " << s.Base::m_A << endl;// 结果:Base'm_A = 10
cout << endl;
//2、通过类名访问:
cout << "通过类名访问:" << endl;
cout << "\tson'm_A = " << son::m_A << endl;// 结果:son'm_A = 20
//第一个 :: 是指通过类名访问,第二个 :: 是指访问父类的作用域
cout << "\tBase'm_A = " << son::Base::m_A << endl;// 结果:Base'm_A = 10
cout << endl;
}
void test02() {
cout << "---------静态成员函数----------" << endl;
cout << endl;
//1、通过对象访问:
cout << "通过对象访问:" << endl;
son s;
//直接访问 得到的是子类中的静态成员函数
s.func();//结果:son'func()
//通过作用域可以访问 父类下的静态成员函数
s.Base::func();//结果:Base'func()
cout << endl;
//2、通过类名访问:
cout << "通过类名访问:" << endl;
son::func();
//第一个 :: 的含义是通过类名访问,第二个 :: 的含义是作用域
son::Base::func();
}
int main() {
test01();
test02();
return 0;
}
七、多继承语法
在实际的开发中一般不建议使用多继承,出现同名成员处理比较麻烦
语法:
class 子类 : 继承方式 父类1 , 继承方式 父类2 , …
代码示例:
#include
using namespace std;
//写一个父类1:
class Base1 {
public:
Base1() {
m_A = 10;
}
int m_A;
};
//写一个父类2:
class Base2 {
public:
Base2() {
m_B = 20;
}
int m_B;
};
//写一个子类,继承父类1、父类2
class son :public Base1, public Base2 {
public:
son() {
m_C = 30;
m_D = 40;
}
int m_C;
int m_D;
};
void test01() {
//son 继承了两个父类的所有的变量
//加上 son 自身的两个变量,一共 4 个 int 型变量
cout << "size of son is " << sizeof(son) << endl;//结果为: size of son is 16
}
int main() {
test01();
return 0;
}
八、菱形继承(又称钻石继承)
什么叫菱形继承?
一个父类被两个子类继承,
这两个子类又作为父类被一个新的子类继承,
这种继承模型被称为菱形继
代码示例:
写一个动物类
让动物类被马类继承
同时,让动物类被驴类继承
最后让骡类继承驴类和马类
#include
using namespace std;
//动物类:
class Animal {
public:
int m_age;
};
//马类:
class horse :public Animal{};
//驴类
class donkey :public Animal{};
//骡类
class mule :public horse, public donkey{};
void test01() {
//测试 mule 的大小:
// mule 分别从两个父类中继承了一个 int 型变量,因此一共有两个 int 型变量
cout << "size of mule is " << sizeof(mule) << endl;// 8
mule m;
//未使用关键字 virtual 写成 m.m_age = 10; 会导致不明确
//因此改写成:
m.horse::m_age = 10;
m.donkey::m_age = 20;//必须添加一个作用域
//打印测试:
cout << "mule'horse'm_age is " << m.horse::m_age << endl;
cout << "mule'donkey'm_age is " << m.donkey::m_age << endl;
}
int main() {
test01();
return 0;
}
结果:
//不采用 virtual 写法的代码:
#include
using namespace std;
//动物类:
class Animal {
public:
int m_age;
};
//马类:
//相比之前的代码,这里这里添加了 virtual 变成了虚继承
class horse :virtual public Animal {};
//驴类
//同样 这里这里添加了 virtual 变成了虚继承
class donkey :virtual public Animal {};
//骡类
class mule :public horse, public donkey {};
void test01() {
//测试 mule 的大小:
// mule 中有两个指针指向一块 int 型变量空间,一共 3*4 bit
cout << "size of mule is " << sizeof(mule) << endl;// 12
mule m;
//使用关键字 virtual,不会导致指代不明确
m.m_age = 9;
m.horse::m_age = 10;
m.donkey::m_age = 20;//必须添加一个作用域
//打印测试:
cout << "mule'm_age is " << m.m_age << endl;//20
cout << "mule'horse'm_age is " << m.horse::m_age << endl;//20
cout << "mule'donkey'm_age is " << m.donkey::m_age << endl;//20
//说明 :使用了 virtual 会使得所有的 m_Age 为一块空间
}![在这里插入图片描述](https://img-blog.csdnimg.cn/80ba838ff2b44729a4796b1b4d0f011f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56CB5oGp,size_20,color_FFFFFF,t_70,g_se,x_16)
int main() {
test01();
return 0;
}
结果:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)