C++黑马1.5倍速跟着敲,gpt + 百度 + csdn辅助理解
目录
🔑继承
继承是面向对象三大特性之一
有些类与类之间存在特殊的关系,例如下图👇

定义这些类时,下级别成员除了拥有上一级的共性,还有自己的特性
这时我们可以利用继承,减少重复代码
🌳基本语法
例如很多网站前端代码中,都有公共的头部,底部和左侧列表,只有中心内容不同
这时继承的意义就体现出来了
语法
class 子类: 继承方式 父类
//eg:
class A: public B
//比如 下面代码中
class Java: public BasePage
class Python: public BasePage
class Cpp: public BasePage
子类 == 派生类
父类 == 基类
子类继承父类的东西
派生类的成员,包含2部分:
1,从基类(父类)继承过来的
2,自己增加的成员
(基类继承的,表现共性;新增的,表现个性)
先看不用继承的
普通实现
#include<iostream>
using namespace std;
//普通实现
//JAVA
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 test01()
{
Java ja;
ja.header(), ja.footer(), ja.left(), ja.content();
cout<<"-----------------------------------"<<endl;
Python py;
py.header(), py.footer(), py.left(), py.content();
cout<<"-----------------------------------"<<endl;
Cpp cp;
cp.header(), cp.footer(), cp.left(), cp.content();
cout<<"-----------------------------------"<<endl;
}
int main()
{
test01();
system("pause");
return 0;
}
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java Python C++...(公共分类列表)
Java学课视频
-----------------------------------
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java Python C++...(公共分类列表)
Python学课视频
-----------------------------------
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java Python C++...(公共分类列表)
C++学科视频
-----------------------------------
请按任意键继续. . .
继承实现
关键代码:
class Java: public BasePage
{};
#include<iostream>
using namespace std;
//继承实现
class BasePage //公共页面的类
{
public:
void header()
{
cout<<"首页, 公开课...(公共头部)"<<endl;
}
void footer()
{
cout<<"帮助中心, 唧唧歪歪(公共底部)"<<endl;
}
void left()
{
cout<<"Java Python C++...(公共分类列表)"<<endl;
}
};
//Java页面
class Java: public BasePage //写完类的声明后 : public 类名 即可继承
{
public:
void content()
{
cout<<"Java 学课"<<endl;
}
};
//Python页面
class Python: public BasePage
{
public:
void content()
{
cout<<"Python 学课"<<endl;
}
};
//C++页面
class Cpp: public BasePage //写完类的声明后 : public 类名 即可继承
{
public:
void content()
{
cout<<"C++ 学课"<<endl;
}
};
void test01()
{
Java ja;
ja.header(), ja.footer(), ja.left(), ja.content();
cout<<"-----------------------------------"<<endl;
Python py;
py.header(), py.footer(), py.left(), py.content();
cout<<"-----------------------------------"<<endl;
Cpp cp;
cp.header(), cp.footer(), cp.left(), cp.content();
cout<<"-----------------------------------"<<endl;
}
int main()
{
test01();
system("pause");
return 0;
}
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java Python C++...(公共分类列表)
Java 学课
-----------------------------------
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java Python C++...(公共分类列表)
Python 学课
-----------------------------------
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java Python C++...(公共分类列表)
C++ 学课
-----------------------------------
请按任意键继续. . .
继承实现,72行了,比普通实现的92行少了20行
🌳继承方式
继承语法
class 子类: 继承方式 父类
继承方式有3种
1,公共继承
2,保护继承
3,私有继承

#include<iostream>
using namespace std;
//继承方式
//公共继承
class Basel //第1个父类
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son1: public Basel //子类Son继承父类Basel
{
public:
void func()
{
m_A = 10; //父类种公共权限成员 到子类种依然是公共权限
m_B = 10; //父类 保护权限 到子类还是保护权限
//m_C = 10; //父类 私有权限 子类无法访问
}
};
void test01()
{
Son1 s1;
s1.m_A = 100;
//s1.m_B = 100; //保护权限在类外无法访问
}
//保护继承
class Base2 //第2个父类
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son2:protected Base2
{
public:
void func()
{
m_A = 100; //父类 公共 子类中变保护权限
m_B = 100; //父类 保护 子类中还是保护
//m_C = 100; //父类中私有 子类无法访问
}
};
void test02()
{
Son2 s1;
//s1.m_A = 1000; //Son2中 m_A为保护, 类外无法访问
//s1.m_B = 1000; //Son2中 m_B为保护, 类外无法访问
}
//私有继承
class Base3 //第3个父类
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son3:private Base3
{
public:
void func()
{
m_A = 100; //父类公共 子类中私有
m_B = 100; //父类保护 子类私有
//m_C = 100; //父类私有 子类无法访问
}
};
void test03()
{
Son3 s1;
//s1.m_A = 1000; //Son3私有 类外无法访问
//s1.m_B = 1000; //Son3私有 类外无法访问
}
class GrandSon3:public Son3 //孙子类 继承 儿子类
{
public:
void func()
{
//m_A = 1000; //子类Son3中私有 儿子也无法访问
//m_B = 1000; //同上
}
};
int main()
{
system("pause");
return 0;
}
🌳继承中的对象模型
#include<iostream>
using namespace std;
//继承中的对象模型
class Base
{
public:
int m_A;
private:
int m_C;
protected:
int m_B;
};
class Son:public Base
{
public:
int m_D; //父类3个属性 子类本身有1个属性
};
//利用开发人员命令提示工具查看对象模型
//跳转盘符 F:
//跳转文件路径 cd 具体路径下
//查看命名
//c1 /d1 report......
void test01()
{
//16
//父类所有非静态成员属性 都会被子类继承下去
//父类中私有成员属性 被编译器隐藏 无法访问 但被继承了
cout<<"size of Son = "<<sizeof(Son)<<endl;
}
int main()
{
test01();
system("pause");
return 0;
}
🌳构造和析构顺序
子类继承父类后,创建的子类对象,也会调用父类的构造函数
那么,父类和子类构造和析构顺序,谁先谁后呢?
创建子类时,也会有父类对象的创建
#include<iostream>
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 test01()
{
//Base b; //父类创建在栈上, test01()结束后会调用析构函数
//继承中的构造和析构顺序:
//先构造父类 再构造子类
//析构顺序与构造顺序相反
Son s;
}
int main()
{
test01();
return 0;
}
Base 构造
Son 构造
Son 析构
Base 析构
🌳同名成员
问题:当子类与父类出现同名成员,如果通过子类对象,访问到子类或父类中同名的数据呢?
1,访问子类同名成员 直接访问
2,访问父类同名成员 加作用域(不论同名属性,还是同名函数,都遵循这一规则)
#include<iostream>
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;
}
int m_A;
};
class Son:public Base
{
public:
Son()
{
m_A = 222;
}
void func()
{
cout<<"Son - func()调用"<<endl;
}
int m_A;
};
//同名成员属性
void test01()
{
Son s;
cout<<"Son 的 m_A = "<<s.m_A<<endl;
//通过子类对象 访问父类同名成员 要加作用域
cout<<"Base 的 m_A = "<<s.Base::m_A<<endl; //加个父类作用域
}
//同名成员函数
void test02()
{
Son s;
s.func(); //直接调用, 调用的是子类中同名函数
//如何调用父类中同名成员函数?
s.Base::func();
//子类出现和父类同名的成员函数 子类同名函数会隐藏掉父类所有同名函数
//如果想访问父类中被隐藏的同名函数, 请加作用域
s.Base::func(100);
}
int main()
{
test01();
test02();
return 0;
}
Son 的 m_A = 222
Base 的 m_A = 100
Son - func()调用
Base - func()调用
Base - func(int a)调用
🌳同名静态成员
静态成员和非静态成员,处理方式一致
1,子类,直接访问
2,父类,加作用域
和上一个视频几乎一样,只是静态成员有2种访问方式
#include<iostream>
using namespace std;
//继承中同名静态成员处理方式
class Base
{
public:
//静态: 编译阶段分配内存 所有对象共享数据 类内声明 类外初始化
static int m_A;
static void func()
{
cout<<"Base - static void func()"<<endl;
}
static void func(int a)
{
cout<<"Son - static void func(int a)"<<endl;
}
};
int Base::m_A = 100; //静态成员 类外初始化
class Son:public Base
{
public:
static int m_A;
static void func()
{
cout<<"Son - static void func()"<<endl;
}
};
int Son::m_A = 166;
//同名静态成员属性
void test01()
{
//静态成员访问方式2种
//1,通过对象访问
cout<<"对象访问"<<endl;
Son s;
cout<<"Son 下 m_A = "<<s.m_A<<endl;
cout<<"Base 下 m_A = "<<s.Base::m_A<<endl;
//2,通过类名访问
cout<<"类名访问"<<endl;
cout<<"Son 下 m_A = "<<Son::m_A<<endl;
//第一个:: 表示通过类名访问
//第2个 :: 表示访问父类作用域下
cout<<"Base 下 m_A = "<<Son::Base::m_A<<endl;
}
//同名静态成员函数
void test02()
{
//1,通过对象访问
cout<<"通过对象"<<endl;
Son s;
s.func();
s.Base::func();
cout<<endl;
//2,通过类名访问
cout<<"通过类名"<<endl;
Son::func();
//Son::类名访问 Base::父类作用域
Son::Base::func();
//Son::func(100); //需要加作用域
Son::Base::func(100);
}
int main()
{
//test01();
test02();
return 0;
}
通过对象
Son - static void func()
Base - static void func()
通过类名
Son - static void func()
Base - static void func()
Son - static void func(int a)
🌳多继承语法
C++允许一个类继承多个类
语法
class 子类 : 继承方式 父类1, 继承方式 父类2...也就是你可以有多个爹🤭
多继承父类可能存在同名成员,要加作用域
C++实际开发不用多继承
总结:多继承中不同父类出现同名成员,子类调用它们时要加作用域
#include<iostream>
using namespace std;
//多继承语法
class Base1
{
public:
Base1()
{
m_A = 111;
}
int m_A;
};
class Base2
{
public:
Base2()
{
m_A = 222;
}
int m_A;
};
//子类 继承Base1和Base2
//语法: class 子类:继承方式 父类1, 继承方式 父类2...
class Son:public Base1, public Base2 //是1个冒号,表示继承, 2个冒号是作用域
{
public:
Son()
{
m_C = 333;
m_D = 444;
}
int m_C, m_D;
};
void test01()
{
Son s;
cout<<"sizeof Son = "<<sizeof(s)<<endl; //4*4 == 16
//当不同父类出现同名成员, 加作用域区分
//cout<<"m_A = "<<s.m_A<<endl;
cout<<"Base1 ::m_A = "<<s.Base1::m_A<<endl;
cout<<"Base2 ::m_A = "<<s.Base2::m_A<<endl;
}
int main()
{
test01();
return 0;
}
sizeof Son = 16
Base1 ::m_A = 111
Base2 ::m_A = 222
🌳菱形继承
虚继承,可解决菱形继承,但因为是多继承,写项目不建议用,但是面试可能会考到
概念:
两个派生类(子类)继承同一个基类(父类)
又有某个类同时继承两个派生类
成为菱形(钻石)继承
或者
1,羊继承了动物,驼也继承了动物,当草泥马使用数据,会产生二义性
2,草泥马继承自动物的数据,有2份,但是我们只需要1份

关键代码
//羊类
class Sheep:virtual public Animal{};
//驼类
class Tuo:virtual public Animal{};
#include<iostream>
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 test01()
{
SheepTuo st;
st.Sheep::m_Age = 18;
st.Tuo::m_Age = 45;
//菱形继承, 两个父类拥有相同数据, 请加作用域
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;
//这份数据, 有1份就行, 但是菱形继承存在2个父类, 资源浪费
}
int main()
{
test01();
return 0;
}
st.Sheep::m_Age = 45
st.Tuo::m_Age = 45
st.m_Age = 45
🌼总结
C++的学习,不仅需要学习使用,还要学习底层,难是难一点,为难有所得吧
面试考到的很多语法,黑马C++多少都会说到,学就是了
总好过,看学校的书看不进去
826

被折叠的 条评论
为什么被折叠?



