你的c++学习路上明灯
你的c++学习路上明灯_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV16P4y1M7cX?p=10
目录
2.注意我上面的那句话,无法访问到,这就说明了,父类中私有成员也会被子类继承,只是由编译器隐藏后访问不到了。
5.同名静态成员处理方式和非静态处理方式一样,只不过有两种访问方式(通过对象,通过类名)
3.重写:函数返回值类型 函数名,参数列表完全一致称为重写。
学习c++的人一定知道的就是c++是面向对象设计的,而面对对象的三大特性就是封装,继承和多态,我们在刚开始学习的时候就已经学过封装了,今天我们主要来学习一下多态和继承。
类的定义的出现,是具有革命性意义的,而继承和多态就是让c++变得更为方便的一笔。
继承:
一,基本介绍:
1,好处:
减少重复代码。
2,语法:
class 子类(派生类) : 继承方式 父类(基类)
3,
派生类中的成员包含两大部分:
一部分是从基类中继承来的东西,另一部分是自己增加的部分
从基类继承过来的表现其共性,而新增成员体现其个性
二,详细的使用
1.继承方式:
1)公共继承:父类权限不变;
2)保护继承:全部变成保护权限
3)私有继承:全部变为私有权限
上述三种继承方式都无法访问到分类的私有权限下的内容,但是可以访问到保护权限下的。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
//普通实现页面
//需要大量的重复代码,冗余。
//class Java {
//public:
//
// void header() {
// cout << "首页,公开课。。。。(公共头部)" << endl;
// }
// void footer() {
// cout << "帮助中心,交流合作。。。(公共底部)" << endl;
// }
// void content() {
// cout << "Java学科视频" << endl;
// }
//
//};
//
//class Python {
//public:
//
// void header() {
// cout << "首页,公开课。。。。(公共头部)" << endl;
// }
// void footer() {
// cout << "帮助中心,交流合作。。。(公共底部)" << endl;
// }
// void content() {
// cout << "Python学科视频" << endl;
// }
//
//};
//class Cpp {
//public:
//
// void header() {
// cout << "首页,公开课。。。。(公共头部)" << endl;
// }
// void footer() {
// cout << "帮助中心,交流合作。。。(公共底部)" << endl;
// }
// void content() {
// cout << "Cpp学科视频" << endl;
// }
//
//};
//继承页面
// 重复的部分只用写一次。
//公共页面类
class basepage {
public:
void header() {
cout << "首页,公开课。。。。(公共头部)" << endl;
}
void footer() {
cout << "帮助中心,交流合作。。。(公共底部)" << endl;
}
};
class Java : public basepage {
public:
void content() {
cout << "Java学科视频" << endl;
}
};
class Python : public basepage {
public:
void content() {
cout << "Python学科视频" << endl;
}
};
class Cpp :public basepage {
public:
void content() {
cout << "Cpp学科视频" << endl;
}
};
void test1() {
cout << "Java下载视频如下:" << endl;
Java ja;
ja.content();
ja.footer();
ja.header();
cout << "------------------" << endl;
cout << "Python下载视频如下:" << endl;
Python py;
py.content();
py.footer();
py.header();
cout << "------------------" << endl;
cout << "Cpp下载视频如下:" << endl;
Cpp cp;
cp.content();
cp.footer();
cp.header();
cout << "------------------" << endl;
}
int main() {
test1();
return 0;
}
2.注意我上面的那句话,无法访问到,这就说明了,父类中私有成员也会被子类继承,只是由编译器隐藏后访问不到了。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class base {
public:
int m_A;
private:
int m_B;
protected:
int m_C;
};
class son1 :public base {
public:
int m_D;
};
//父类所有的非静态成员属性都会被子类继承下去
//父类中的私有成员属性是被编译器给隐藏了。因此访问不到,但是确实是被继承下来了
void test1() {
cout << "son1 的大小为:" << sizeof(son1) << endl;
//所以此处的大小是16;
}
int main(){
test1();
return 0;
}
3.继承中构造函数和析构函数的调用顺序
创建子类对象后,先构造父类,再构造子类,析构顺序相反。
4.同名成员处理
1)子类对象可以直接访问到子类中的同名成员,
2)子类对象加作用域可以访问到父类同名成员
3)当子类与父类拥有同名的成员函数,子类会隐藏父类中的同名函数,一定要加作用域才能够访问
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class base {
public:
int m_A=200;
void func() {
cout << "base-func()函数的调用" << endl;
}
void func(int a) {
cout << "base-func(int a)函数的调用" << endl;
}
};
class son1 :public base {
public:
int m_A=100;
void func() {
cout << "son-func()函数的调用" << endl;
}
};
//同名成员函数处理
void test1() {
son1 s;
//子类对象可以直接访问到子类中的同名成员
s.func();
//子类对象加作用域可以访问到父类的同名成员
s.base::func();
//当子类对象与父类对象拥有同名的成员函数,子类会隐藏父类中的同名函数,一定要加作用域才能够访问到哦
}
//同名成员属性处理
void test2() {
son1 s;
cout << s.m_A << endl;
cout << s.base::m_A << endl;
}
int main() {
test1();
test2();
return 0;
}
5.同名静态成员处理方式和非静态处理方式一样,只不过有两种访问方式(通过对象,通过类名)
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Base {
public:
static int m_A;
static void func() {
cout << "Base-func()的调用" << endl;
}
static void func(int a) {
cout << "Base-func(int a)的调用" << endl;
}
};
int Base::m_A = 100;
class Son:public Base {
public:
static int m_A;
static void func() {
cout << "Son-func()的调用" << endl;
}
};
int Son::m_A = 200;
void test1() {
//1.通过对象访问
Son s;
cout << "通过对象访问" << endl;
cout << s.m_A << endl;
cout << s.Base::m_A << endl;
//2,通过类名访问
cout << "通过类名访问" << endl;
cout << Son::m_A << endl;
//第一个 ::代表通过类名访问,第二个 ::代表作用域
cout << Son::Base::m_A << endl;
}
int main() {
test1();
return 0;
}
//同名静态成员处理方式和非静态成员处理方式一样,只不过是有了两种访问方式
//通过类名和通过对象
6.多继承语法
1)c++允许一个类继承多个类(一个子类继承多个父类)
2)多继承可能会引发父类中有同名成员出现,需要加一个作用域区分
3)c++实际开发不建议用多继承(容易引发一些不必要的冲突)
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Base1 {
public:
int m_A;
Base1() {
m_A = 100;
}
};
class Base2 {
public:
int m_A;
Base2() {
m_A = 200;
}
};
class Son :public Base1, public Base2 {
public:
int m_C;
Son() {
m_C = 300;
}
};
void test1() {
Son s;
//大小依然是所有的数据大小之和
cout << sizeof(s) << endl;
//多继承中如果父类中出现了同名情况,子类使用的时候要加作用域
cout << s.Base1::m_A << endl;
cout << s.Base2::m_A << endl;
}
int main() {
test1();
return 0;
}
7.菱形继承
菱形继承带来的问题:
子类继承两份相同的数据,导致资源浪费和二义性。
可以用虚继承的方法来解决
所谓虚继承每一个派生类会给自己的子类继承虚基类指针(vbptr)和一份虚基类表,表中记录了虚基类与本类与本类的偏移量。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Animal {
public:
int m_Age;
};
//虚继承就是再继承方式的前面加上virtual关键字
//虚继承就是菱形继承问题的解决方法
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;
st.tuo::m_Age = 200;
cout << st.sheep::m_Age << endl;
cout << st.tuo::m_Age << endl;
}
int main() {
test1();
return 0;
}
多态:
一,基本介绍
多态分为两类:
1)静态多态:函数重载和运算符重载,复用函数名
2)动态多态:派生类和虚函数实现运行时多态。
区别:静态多态的函数地址早绑定---编译阶段确定函数地址
动态多态的函数地址晚绑定---运行阶段确定函数地址
***c++中允许父子类之间的类型转换
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Animal {
public:
//函数前面加上virtual关键字,变成虚函数,那么编译器在编译时就不能确定函数调用了
//即:函数地址的先后绑定
virtual void Speak() {
cout << "动物在说话" << endl;
}
};
class Cat :public Animal {
public:
//重写:函数返回值类型 函数名 参数列表 完全一致
//所以这里的virtual可写可不写
virtual void Speak() {
cout << "小猫在说话" << endl;
}
};
class Dog :public Animal {
public:
void Speak() {
cout << "小狗在说话" << endl;
}
};
//回调函数,提供多个选择
//c++中允许父子类之间的类型转化
void dospeak(Animal &animal) {
animal.Speak();
}
void test1() {
Cat cat;
dospeak(cat);
Dog dog;
dospeak(dog);
}
int main() {
test1();
return 0;
}
二,详细的使用
1.动态多态满足条件:
1)有继承关系
2)子类重写父类的虚函数
2.使用动态多态:
父类的指针或引用指向子类对象
3.重写:函数返回值类型 函数名,参数列表完全一致称为重写。
4.多态的优点
1)代码组织结构清晰
2)可读性强
3)利于前期和后期的扩展以及维护
5.纯虚函数
virtual 返回值类型 函数名 (参数列表)=0;
6.抽象类特点:
1)无法实例化对象
2)子类必须重写抽象类中的纯虚函数,否则也属于抽象类。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Base {
public:
//纯虚函数
//父类的虚函数是用不上的,写了也是白写,所以就出现了纯虚函数的概念
virtual void func() = 0;
//一旦有了纯虚函数,该类就称作抽象类
//不能实例化对象
//且子类也必须重写虚函数,不然子类也成了抽象类,也无法实例化对象
};
class Son : public Base {
public:
void func() {
cout << "func()函数的调用" << endl;
}
};
void test1() {
//多态的意义就是
//定义一个父类的指针,指向它的任意一个我们想要使用的子类对象,
//从而能使我们调用到该子类对象的函数实现
Base* b = new Son;
b->func();
delete b;
}
int main() {
test1();
return 0;
}
7.虚析构和纯虚析构的共性
1)可以解决父类指针释放子类对象时不干净
2)都需要有具体的函数实现
区别:如果是纯虚析构,该类属于抽象类,无法实例化对象。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<string>
class Animal {
public:
virtual void Speak() = 0;
Animal() {
cout << "Animal构造函数的调用" << endl;
}
//利用纯析构可以解决父类指针释放子类对象时不干净的问题
/*virtual ~Animal() {
cout << "Animal析构函数的调用" << endl;
}*/
//如果不想让该类实例化对象,就写成纯虚析构
virtual ~Animal() = 0;
};
Animal::~Animal() {
cout << "Animal纯虚析构函数的调用" << endl;
}
class Cat :public Animal {
public:
virtual void Speak() {
cout << "小猫在说话" << endl;
}
Cat(string name) {
cout << "Cat构造函数的调用" << endl;
m_Name = new string(name);
}
~Cat() {
cout << "Cat析构函数的调用" << endl;
if (m_Name != NULL) {
delete m_Name;
m_Name = NULL;
}
}
string* m_Name;
};
void test1() {
Animal* a = new Cat("Tom");
a->Speak();
//父类指针在析构的时候,并不会调用子类中的析构函数,导致子类如果有堆区属性,会出现内存泄漏
delete a;
}
int main() {
test1();
return 0;
}
8.实例
给大家两个实例练练手
1)
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
//制作饮品-多态
class MakeDrink {
public:
//煮水
virtual void Boil() = 0;
//冲泡
virtual void Brew() = 0;
//倒入杯中
virtual void Pour() = 0;
//加入辅料
virtual void Add() = 0;
void makedrink() {
Boil();
Brew();
Pour();
Add();
}
};
//制作咖啡
class Coffee : public MakeDrink {
public:
//煮水
virtual void Boil() {
cout << "煮咖啡水" << endl;
}
//冲泡
virtual void Brew() {
cout << "冲泡咖啡" << endl;
}
//倒入杯中
virtual void Pour() {
cout << "倒入咖啡杯中" << endl;
}
//加入辅料
virtual void Add() {
cout << "加入牛奶和糖" << endl;
}
};
//制作茶
class Tea : public MakeDrink {
public:
//煮水
virtual void Boil() {
cout << "煮茶水" << endl;
}
//冲泡
virtual void Brew() {
cout << "冲泡茶" << endl;
}
//倒入杯中
virtual void Pour() {
cout << "倒入茶杯中" << endl;
}
//加入辅料
virtual void Add() {
cout << "加入茶叶" << endl;
}
};
void dodrink(MakeDrink * md) {//MakeDrink * md = 子类对象
md->makedrink();
delete md;
}
void test1() {
//MakeDrink* md = new Coffee;
//MakeDrink& md = new Coffee;
dodrink(new Coffee);
cout << "-----------------" << endl;
dodrink(new Tea);
}
int main() {
test1();
return 0;
}
2)制作电脑
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
//抽象不同的零件类
//抽象CPU类
class CPU {
public:
virtual void calculate() = 0;
};
//抽象显卡类
class xianka{
public:
virtual void display() = 0;
};
//抽象内存条类
class Memory {
public:
virtual void storage() = 0;
};
//电脑类
class Computer {
public:
Computer(CPU* cpu,xianka* xk,Memory* mem) {
m_mem = mem;
m_xk = xk;
m_cpu = cpu;
}
//提供工作的函数
void work() {
m_cpu->calculate();
m_xk->display();
m_mem->storage();
}
~Computer() {
if (m_cpu != NULL) {
delete m_cpu;
m_cpu = NULL;
}
if (m_xk != NULL) {
delete m_xk;
m_xk = NULL;
}
if (m_mem != NULL) {
delete m_mem;
m_mem = NULL;
}
}
private:
CPU* m_cpu;
xianka* m_xk;
Memory* m_mem;
};
//具体厂商
//inter厂商
class IntelCPU :public CPU {
public:
virtual void calculate() {
cout << "Inter的CPU" << endl;
}
};
class Intelxianka :public xianka {
public:
virtual void display() {
cout << "Inter的xianka" << endl;
}
};
class IntelMemory :public Memory {
public:
virtual void storage() {
cout << "Inter的Memory" << endl;
}
};
//联想厂商
class Lenovo :public CPU {
public:
void calculate() {
cout << "Lenovo的CPU" << endl;
}
};
class Lenovoxianka :public xianka {
public:
void display() {
cout << "Lenovo的xianka" << endl;
}
};
class LenovoMemory :public Memory {
public:
void storage() {
cout << "Lenovo的Memory" << endl;
}
};
void test1() {
//创建第一台电脑
CPU* intelCpu = new IntelCPU;
xianka* intelxianka = new Intelxianka;
Memory* intelmem = new IntelMemory;
Computer computer1(intelCpu, intelxianka, intelmem);
computer1.work();
cout << "------------------" << endl;
//创建第二台电脑
Computer computer2(new IntelCPU, new Intelxianka, new IntelMemory);
computer2.work();
}
int main() {
test1();
return 0;
}
东西很多,希望大家认真学习,我后面会在B站上面更新讲解视频,希望大家捧场。