C++ 继承详解,代码示例,通俗易懂

C++ 继承详解,代码示例,通俗易懂,第1张

C++继承详解,代码示例,通俗易懂

一、基本语法

继承:面向对象的三大特性之一

使用例子模拟实现的方法来理解更加容易:

模拟一个学习网页的页面
一个网站有很多的网页,每个网页有相同的部分和不同的部分
各个网页相同的部分可以采用继承的方法来写,这样就避免了写重复的代码

不采用继承

首先来看看 不采用 继承 技术来写的代码-----超级菜鸟级别:

#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;
}

八、菱形继承(又称钻石继承)

什么叫菱形继承?
一个父类被两个子类继承,
这两个子类又作为父类被一个新的子类继承,
这种继承模型被称为菱形继
代码示例:
写一个动物类
让动物类被马类继承
同时,让动物类被驴类继承
最后让骡类继承驴类和马类

不采用 virtual 写法的代码:

#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 写法的代码:
//不采用 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;
}

结果:

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/562833.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-02
下一篇 2022-04-02

发表评论

登录后才能评论

评论列表(0条)

保存