土豆的老家陕西安康!怪舒服的咯,广西一眼望去全是房子啦,小时候一眼开敞水田再也回不来啦
目录
五,继承
5.1 基本语法
5.2 继承方式
5.3 继承中的对象模型
5.4 构造和析构顺序
5.5 同名成员处理
5.6 同名静态成员处理
5.7 多继承语法
5.8 菱形继承问题及解决办法
六,多态
6.1 基本语法
6.2 原理剖析
6.3 案例-计算器类
6.4 纯虚函数和抽象类
6.5 案例-制作饮品
6.6 虚析构和纯虚析构
五,继承
5.1 基本语法
语法:class 子类(派生类):继承方式 父类(基类)
调用时只需要创建子类的对象,就可以使用父类的函数和变量
#include<iostream>
using namespace std;
class Basepage//公共页面
{
public:
void header() {
cout << "首页,公开课,登录,注册……(公共头部)" << endl;
}
void footer() {
cout << "帮助中心,交流合作,站内地图……(公共底部)" << endl;
}
void left() {
cout << "Java.,C++,Python……(公共分类列表)" << endl;
}
};
class Java :public Basepage//继承公共的页面
{
public:
void content() {
cout << "Java学科视频" << endl << endl;
}
};
class CPP :public Basepage//继承公共的页面
{
public:
void content() {
cout << "Cpp学科视频" << endl << endl;
}
};
class Python :public Basepage//继承公共的页面
{
public:
void content() {
cout << "Python学科视频" << endl << endl;
}
};
void test01() {
cout << "Java下载视频页面如下" << endl;
Java ja;
ja.header();
ja.footer();
ja.left();
ja.content();
CPP cpp;
cpp.header();
cpp.footer();
cpp.left();
cpp.content();
Python py;
py.header();
py.footer();
py.left();
py.content();
}
int main()
{
test01();
system("pause");
return 0;
}
5.2 继承方式
父类私有权限内容均不可访问
公共继承【公共-公共,保护-保护】,保护继承【公共+保护-- 保护】,私有继承【公共+保护--私有】
#include<iostream>
using namespace std;
class Base
{
public:
int _a;
protected:
int _b;
private:
int _c;
};
class son1 :public Base
{
public:
void func() {
_a = 10;//公共
_b = 10;//保护
//_c = 10;//私有
}
};
class son2 :protected Base
{
public:
void func() {
_a = 99;//公共变保护
_b = 99;//保护
//_c = 99;
}
};
class son3 :private Base
{
public:
void func() {
_a = 34;//公共变私有
_b = 34;//保护变私有
//_c = 34;
}
};
class grandson3 :public son3
{
public:
//_a = 199;son3的对象都是私有的
};
void test01() {
son1 s1;
s1._a = 100;
//s1._b = 100;//保护,类外不可访问
son2 s2;
//s2._a = 120;//保护,类外不可访问
}
int main()
{
test01();
system("pause");
return 0;
}
5.3 继承中的对象模型
父类中不可访问的对象只是隐藏了,全继承
开发人员命令提示工具——如果文件在C盘-回车,不在C盘,盘:(冒号)回车——cd (空格)——复制文件路径-回车——dir-回车——cl /d1 reportSingleClassLayout-查看的类 空格 "文件名.后缀"——回车
CL /D1 ……(首字母大写,不空格)查看的类(大小写照搬)空格 文件名(写开头两个字符,TAB键自动补上,双引号无所谓)
#include<iostream>
using namespace std;
class Base
{
public:
int _a;
protected:
int _b;
private:
int _c;
};
class son1 :public Base
{
public:
int _d;
};
void test01() {
cout << "sizeof son1=" << sizeof(son1) << endl;//16
}
int main()
{
test01();
system("pause");
return 0;
}
5.4 构造和析构顺序
BASE构造——SON1构造——SON1析构——BASE析构
#include<iostream>
using namespace std;
class Base
{
public:
Base() {
cout << "Base 构造 函数" << endl;
}
~Base() {
cout << "Base 析构 函数" << endl;
}
};
class son1 :public Base
{
public:
son1() {
cout << "son1 构造 函数" << endl;
}
~son1() {
cout << "son1 析构 函数" << endl;
}
};
void test01() {
son1 ss1;
}
int main()
{
test01();
system("pause");
return 0;
}
5.5 同名成员处理
访问子类同名成员,直接访问;访问父类同名(包括重载)成员,加作用域
#include<iostream>
using namespace std;
class Base
{
public:
Base() {
m_a = 100;
}
void func() {
cout << "BASE函数\t" << endl;
}
void func(int a) {
cout << "BASE(INT)函数\t" << endl;
}
int m_a;
};
class son1 :public Base
{
public:
son1() {
m_a = 900;
}
void func() {
cout << "SON1函数\t" << endl;
}
int m_a;
};
void test01() {
son1 ss1;
cout << "子类中的SS1\t"<<ss1.m_a << endl;
cout <<"父类中的SS1\t"<< ss1.Base::m_a << endl;
ss1.func();
ss1.Base::func();
//ss1.func(100);//如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数
//如果想访问父类的同名函数,都要加作用域
ss1.Base::func(100);
}
int main()
{
test01();
system("pause");
return 0;
}
5.6 同名静态成员处理
同非静态成员同名情况处理方式一致
#include<iostream>
using namespace std;
class Base
{
public:
static void func() {
cout << "BASE函数\t" << endl;
}
static void func(int a) {
cout << "BASE(INT)函数\t" << endl;
}
static int m_a;
};
int Base::m_a = 100;
class son1 :public Base
{
public:
static void func() {
cout << "SON1函数\t" << endl;
}
static int m_a;
};
int son1::m_a = 999;
void test01() {
son1 ss1;
cout << "通过对象访问数据" << endl;
cout << "son1 的SS1\t"<<ss1.m_a << endl;
cout <<"Base 的SS1\t"<< ss1.Base::m_a << endl;
cout << endl << "通过类名访问数据" <<endl;//静态变量全局共享一个
cout << "son1 的SS1\t" << son1::m_a << endl;
cout << "Base 的SS1\t" << Base::m_a << endl;
cout << "Base 的SS1\t" << son1::Base::m_a << endl;//son1::通过类目的方式访问Base::访问son1下Base作用域的M_A
cout << endl << "通过对象访问函数" <<endl;
ss1.func();
ss1.Base::func();
ss1.Base::func(100);
cout << endl << "通过类名访问函数" << endl;
Base::func();
son1::func();
Base::func(100);
son1::Base::func(100);
}
int main()
{
test01();
system("pause");
return 0;
}
5.7 多继承语法
C++允许一个类继承多个类,语法:CLASS 子类:继承方式 父类1,继承方式,父类2……
父类中同名成员作用域区分,实际开发不建议使用
#include<iostream>
using namespace std;
class Base
{
public:
Base() {
_a = 100;
}
int _a;
};
class Base2
{
public:
Base2() {
_a = 99;
_b = 200;
}
int _a;
int _b;
};
class son :public Base,public Base2
{
public:
son() {
_c = 300;
_d = 400;
}
int _c;
int _d;
};
void test01() {
son ss;
cout << "sizeof(son)=\t" << sizeof(son) << endl;//全继承
cout << "Base _a=\t" << ss.Base::_a << endl;
cout << "Base2 _a=\t" << ss.Base2::_a << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
5.8 菱形继承问题及解决办法
两个派生类继承同一个基类,又有某个类同时继承两个派生类——菱形(钻石)继承
问题:孙子类使用数据的时候会产生二义性,爷爷类的数据继承了两份,实际上只需要继承一份
解决办法:虚继承: 关键字VIRTUAL,虚基类
VBPTR: V-IRTUAL, B-BASE, PTR-POINTER 虚基类指针,指向,VBTABLE虚基类表,
#include<iostream>
using namespace std;
class animal
{
public:
int _big;
};
class sheep:virtual public animal {};//虚继承,animal类成为虚基类
class tuo :virtual public animal {};
class sheeptuo :public sheep,public tuo {};
void test01() {
sheeptuo st;
st.tuo::_big = 89;
st.sheep::_big = 42;//共享一个数据,相当于给同一个数据赋值两次
cout << "st._big=\t" << st._big << endl;//虚继承之后可以这么写,该数据只有一个
cout << "st.tuo::_big=\t" << st.tuo::_big << endl;
cout << "st.sheep::_big=\t" << st.sheep::_big << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
六,多态
6.1 基本语法
静态多态:函数重载,运算符重载,复用函数名
动态多态:派生类和虚函数实现运行时多态
区别:静态多态的函数地址早绑定-编译阶段确定函数地址
动态多态的函数地址晚绑定-运行阶段确定函数地址
动态多态满足条件:有继承关系,子类重写父类的虚函数(函数返回值,名称,参数列表完全相同-子类加不加VIRTUAL都行)
使用条件:父类的指针或者引用,指向子类的对象
#include<iostream>
using namespace std;
class animal
{
public:
//加VIRTUAL关键字,实现晚绑定--小猫说话
virtual void speak() {
cout << "动物在说话" << endl;
}
};
class dog :public animal{
public:
void speak() {
cout << "小狗在说话" << endl;
}
};
class cat:public animal {
public:
void speak() {
cout << "小猫在说话" << endl;
}
};
//地址早绑定,在编译阶段确定函数地址
//想猫说话,地址不能提前绑定,运行阶段再绑定,--》地址晚绑定
void dospeak(animal &animal) {
animal.speak();
}
void test01() {
cat catt;
dospeak(catt);//父类的引用,接收了子类的对象,C++允许父类子类之间的类型转换 动物说话
dog dogg;
dospeak(dogg);//根据传入的对象不同执行函数
}
int main()
{
test01();
system("pause");
return 0;
}
6.2 原理剖析
子类父类都记录了一个指针
#include<iostream>
using namespace std;
class animal
{
public:
//加VIRTUAL关键字,实现晚绑定--小猫说话
virtual void speak() {
cout << "动物在说话" << endl;
}
};
class dog :public animal{
public:
void speak() {
cout << "小狗在说话" << endl;
}
};
class cat:public animal {
public:
void speak() {
cout << "小猫在说话" << endl;
}
};
//地址早绑定,在编译阶段确定函数地址
//想猫说话,地址不能提前绑定,运行阶段再绑定,--》地址晚绑定
void dospeak(animal &animal) {
animal.speak();
}
void test01() {
cat catt;
dospeak(catt);//父类的引用,接收了子类的对象,C++允许父类子类之间的类型转换 动物说话
dog dogg;
dospeak(dogg);//根据传入的对象不同执行函数
}
void test02() {
cout << "sizeof(animal)=\t" << sizeof(animal) << endl;//不是虚函数,1,虚函数8,一个指针
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
6.3 案例-计算器类
多态优点:代码组织结构清晰,可读性强,利于前期和后期的扩展及维护
#include<iostream>
using namespace std;
class Caculator
{
public:
int num_;
int num_1;
int Getresult(string oper) {
if (oper == "+") {
return num_ + num_1;
}
else if (oper == "-") {
return num_ - num_1;
}
else if (oper == "*") {
return num_ * num_1;
}
else if (oper == "/" && num_1 != 0) {
return num_ / num_1;
}//如果想扩展新的功能,需要修改源码,真实开发中,开闭原则:开放扩展,关闭修改
}
};
class Abstractcal {//计算机抽象类
public:
virtual int getresult(){
return 0;
}
int _num;
int _num1;
};
class Addcal :public Abstractcal{
int getresult() {
return _num + _num1;
}
};
class Subcal :public Abstractcal {
int getresult() {
return _num - _num1;
}
};
class Mulcal :public Abstractcal {
int getresult() {
return _num * _num1;
}
};
class Bescal :public Abstractcal {
int getresult() {
if (_num1 != 0) {
return _num / _num1;
}
}
};
void test01()
{
Caculator c;
c.num_ = 90;
c.num_1 = 23;
cout << c.num_ << "+" << c.num_1 << "=" << c.Getresult("+") << endl;
cout << c.num_ << "*" << c.num_1 << "=" << c.Getresult("*") << endl;
cout << c.num_ << "-" << c.num_1 << "=" << c.Getresult("-") << endl;
cout << c.num_ << "/" << c.num_1 << "=" << c.Getresult("/") << endl;
}
void test02() {
//使用条件,父类指针直线子类对象
Abstractcal* abc = new Addcal;//堆区开辟 存放 进行加法运算返回值的空间 返回指针
abc->_num = 23;
abc->_num1 = 2;
cout << abc->_num<< "+" << abc->_num1 << "=" << abc->getresult() << endl;
delete abc;//销毁,堆区的内存释放了,但是指针没有变
abc = new Subcal;
abc->_num = 23;
abc->_num1 = 2;
cout << abc->_num << "-" << abc->_num1 << "=" << abc->getresult() << endl;
delete abc;
abc = new Bescal;
abc->_num = 23;
abc->_num1 = 2;
cout << abc->_num << "/" << abc->_num1 << "=" << abc->getresult() << endl;
delete abc;
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
6.4 纯虚函数和抽象类
多态中,父类中虚函数通常不实现,主要都是调用子类重写的内容,--》纯虚函数--》抽象类
语法:VIRTUAL 返回值类型 函数名(参数列表)=0;
特点:无法实例化对象,子类必须重写抽象类中的纯虚函数,否则也属于抽象类
#include<iostream>
using namespace std;
class Base//有则抽象类,无法实例化对象,子类必须重写纯虚函数否则抽象
{
public:
virtual void func() = 0;//纯虚函数
};
class son:public Base {
public:
void func() {
cout << "func 函数调用" << endl;
};
};
class son2 :public Base {
public:
void func() {
cout << "func2 函数调用" << endl;
};
};
void test01()
{
//Base b;//不允许使用抽象类实例化对象
son a;
a.func();
Base* base = new son;
base->func();
delete base;
base = new son2;
base->func();
}
void test02() {
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
6.5 案例-制作饮品
#include<iostream>
using namespace std;
class AbstractDrinking
{
public:
virtual void Boil() = 0;
virtual void Brew() = 0;
virtual void Pourincup() = 0;
virtual void Putsomething() = 0;
void Makedrinking() {
Boil();
Brew();
Pourincup();
Putsomething();
}
};
class Makecoffee :public AbstractDrinking {
public:
void Boil() {
cout << "烧水至沸腾" << endl;
}
void Brew() {
cout << "冲泡咖啡" << endl;
}
void Pourincup() {
cout << "倒入杯中" << endl;
}
void Putsomething() {
cout << "加入糖和牛奶" <<endl<< endl;
}
};
class Tea :public AbstractDrinking {
public:
void Boil() {
cout << "烧水至沸腾" << endl;
}
void Brew() {
cout << "加入茶叶" << endl;
}
void Pourincup() {
cout << "倒入杯中" << endl;
}
void Putsomething() {
cout << "加入柠檬" <<endl<< endl;
}
};
void dowork(AbstractDrinking* tea) {
tea->Makedrinking();
delete tea;
}
void test01()
{
AbstractDrinking* coffee = new Makecoffee;
coffee->Makedrinking();
delete coffee;
AbstractDrinking* tea = new Tea;
tea->Makedrinking();
delete tea;
dowork(new Tea);
}
int main()
{
test01();
system("pause");
return 0;
}
6.6 虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构
共性:可以解决父类指针释放子类对象,都需要具体的函数体现
区别:纯虚--抽象类--无法实例化对象
虚析构:VIRTUAL ~类名(){ }
纯虚析构:VIRTUAL~类名()=0;需要声明也需要实现
#include<iostream>
using namespace std;
class Animal {
public:
Animal() {
cout << "animal xu构造函数调用" << endl;
}
//改成虚析构,走猫的析构,再走animal的析构,解决父类指针释放子类对象时不干净的问题
//虚析构走了,需要代码实现
/*virtual ~Animal() {
cout << "animal xu析构函数调用" << endl;
}*/
virtual ~Animal() = 0;//纯虚析构,报错,需要声明也需要具体实现,有了即抽象类
virtual void speak() = 0;
};
Animal::~Animal() {
cout << "animal 纯虚析构函数调用" << endl;
}
class Cat :public Animal {
public:
Cat(string name) {
cout << "cat 构造函数调用" << endl;
m_name=new string(name);//堆区开辟空间放名字,返回名字的指针
}
~Cat() {
if (m_name != NULL) {
cout << "cat 析构函数调用" << endl;
delete m_name;
m_name = NULL;
}
}
void speak() {
cout << *m_name<<"miao miao miao " << endl;
}
string* m_name;
};
void test01()
{
Animal* cat = new Cat("汤姆猫");
cat->speak();
//父类指针在析构的时候,不会调用子类中的析构函数,导致子类如果有堆区属性,出现内存泄露(没有释放?)
delete cat;
}
int main()
{
test01();
system("pause");
return 0;
}
不要老在我要DDL的时候找我