c++继承的相关知识点

继承

导航:
1.继承的基础语法
2.继承的方式(成员属性及成员函数)
3.子类继承父类时,构造函数及析构函数的顺序
4.继承同名的成员关系,如何访问
5.访问同名静态成员
6.多继承语法
7.菱形继承

———————————————————————————————————

继承的基础语法
当我们写的时候,如果每个类都有相同的部分,那么通过一个个将其中的内容一个个敲出来将会十分占空间,那么我们就会用到继承

方法:将公共的内容专门写出一个类出来,然后写别的子类时候,加入公共部分即可。
语法:class 子类:继承方式 父类
(其中子类又叫做派生类,父类叫做基类)

下面看例子:
#include <iostream>
#include <string>
using namespace std;

//这里是公共的部分,也就是下面子类都共有的部分,先写出来
class BasePage
{
public:
	void head()
	{
		cout<<"上部的内容:........"<<endl;
	}

	void foot()
	{
		cout<<"下部的内容:........"<<endl;
	}

	void left()
	{
		cout<<"左边的内容:........"<<endl;
	}
};

//子类c++
class Cpp:public BasePage  //这里就可以将公共的部分添加至类中,减少重复内容
{
public:
	void cpp1()
	{
		cout<<"c++的内容"<<endl;
	}
};

class Py:public BasePage  //这里同样也是
{
public:
	void py1()
	{
		cout<<"python的内容"<<endl;
	}
};

void test()
{
	//分别输出对应的自己有的内容和公共的内容
	Cpp c;
	c.head();
	c.foot();
	c.left();
	c.cpp1();

	cout<<"---------"<<endl;

	Py py;
	py.foot();
	py.head();
	py.left();
	py.py1();
}

int main()
{
	test();
	system("pause");
	return 0;
}

运行程序:
执行结果
好处:可以减少很多在子类中重复的内容
———————————————————————————————————
继承方式
公共继承 保护继承 私有继承
若子类公共继承父类,那么除了父类的私有属性访问不到其余与父类对应继承
若子类保护继承父类,那么除了父类的私有属性访问不到其余都为保护继承
若子类私有继承父类,那么除了父类的私有属性访问不到其余都为私有继承

注意在类外,对于类的保护属性以及私有属性都不能访问及修改,公共属性可以访问及修改

例子:

#include <iostream>
#include <string>
using namespace std;
class father
{
public:		
	int a;
protected:
	int b;
private:
	int c;
};

//公共继承
class son1:public father
{
public:
	void func()
	{
		a = 100;  //此时a为公共继承
		b = 100;  //b为保护继承
		//c = 100;  //c访问不到
	}
};

void test01()
{
	son1 s;
	s.a = 100;   //是公共属性可以访问到
	//s.b =200;	 //类外访问不到保护属性
}

//保护继承
class son2:protected father
{
public:
	void func()
	{
		a = 100;  //此时a为保护继承
		b = 100;  //b为保护继承
		//c = 100;  //c访问不到
	}
};

void test02()
{
	son2 s;
	//s.a = 100;	//类外访问不到a
	//s.b =200;	//类外访问不到b
}

//私有继承
class son3:private father
{
public:
	void func()
	{
		a = 100;  //此时a为保护继承
		b = 100;  //b为保护继承
		//c = 100;  //c访问不到
	}
};

void test03()
{
	son3 s;
	//s.a = 100;	//类外访问不到a,因为是私有属性
	//s.b =200;	//类外访问不到b,因为是私有属性
}


int main()
{
	test01();
	system("pause");
	return 0;
}

———————————————————————————————————
父类中的所有非静态成员属性都会被子类继承下去
父类中私有成员属性也会被继承下去,只不过是被编译器隐藏了

子类继承父类时,构造函数与析构函数的顺序?
答:当子类继承父类的时候,先调用父类构造函数,再调用子类构造函数,析构函数与其相反

———————————————————————————————————
继承同名的成员关系
1.子类对象可以直接访问到子类中同名成员
2.子类对象加作用域可以访问到父类同名成员
3.当子类与父类拥有同名的成员函数,子类会隐藏掉父类中同名的成员函数,加作用域可以访问到父类的成员函数
例子:

#include <iostream>
#include <string>
using namespace std;
//父类
class father
{
public:
	father()
	{
		a = 100;
	}

	void func()
	{
		cout<<"父类进行调用"<<endl;
	}

	void func(int a)
	{
		cout<<"a = "<<a<<endl;
	}
	int a;
};

//子类进行公共继承父类
class son:public father
{
public:
	son()
	{
		a = 200;
	}
	void func()
	{
		cout<<"子类进行调用"<<endl;
	}
	int a;
};


//子类父类同名成员属性时候
void test()
{
	son s1;
	cout<<"son中的a:"<<s1.a<<endl;		//直接访问,就可以访问到子类的成员属性
	cout<<"father中的a:"<<s1.father::a<<endl;	//加一个作用域就可以访问到父类的成员属性
}

//同名成员函数
void test01()
{
	son s1;
	s1.func();//直接进行调用子类中的同名函数
	//当父类与子类拥有同样名字的成员函数,编译器会自动隐藏掉父类的成员函数,
	s1.father::func(100);  //加上作用域才能访问父类的成员函数,不能直接调用s1.func(100)
}

int main()
{
	test01();
	system("pause");
	return 0;
}

———————————————————————————————————
访问同名静态成员,与非静态相似
例子:

#include <iostream>
#include <string>
using namespace std;
//定义一个父类
class Base
{
public:
	static void func()
	{
		cout<<"父类的void func()进行调用"<<endl;
	}

	static void func(int a)
	{
		cout<<"父类的static void func(int a)调用"<<endl;
	}
	static int a;
};
int Base::a = 100;

//定义一个子类
class son:public Base
{
public:
	//静态成员函数
	static void func()
	{
		cout<<"子类的void func()进行调用"<<endl;
	}
	static int a;  //类内静态变量初始化
};
int son::a = 200;

//访问静态成员属性
void test01()
{
	//1.通过对象访问静态成员属性
	cout<<"通过对象访问静态成员函数"<<endl;
	son s1; 
	cout<<"son下的静态成员属性"<<s1.a<<endl;      //直接访问类内成员
	cout<<"Base下的静态成员属性"<<s1.Base::a<<endl;	//访问子类时要加作用域

	//2.通过类名来访问
	cout<<"通过类名访问静态成员函数"<<endl;
	cout<<"son下的静态成员属性"<<son::a<<endl;      //直接访问类内成员
	cout<<"Base下的静态成员属性"<<Base::a<<endl;	//访问子类时要加作用域
}

//访问静态成员函数
void test02()
{
	//通过对象访问
	cout<<"通过对象访问"<<endl;
	son s1;
	//s1.func(100);  //若子类成员函数与父类相同时,会隐藏父类的同名成员函数,需要加作用域才能访问
	s1.Base::func(100);
	s1.func();
	s1.Base::func();

	//2.通过类名访问
	cout<<"通过类名访问"<<endl;
	son::func();
	Base::func();
}
int main()
{
	test02();
	system("pause");
	return 0;
}

———————————————————————————————————
多继承语法:class 子类:继承方式 父类1,继承方式 父类2 {};
例子:

#include <iostream>
#include <string>
using namespace std;
class Base1  //父类1
{
public:
	Base1()
	{
		m_a = 100;  //设一个同名m_a
	}
	int m_a;
};
	
class Base2	//父类2
{
public:
	Base2()
	{
		m_a = 200;
	}
	int m_a;
};

class son:public Base1,public Base2  //继承两个父类
{
public:
	son()
	{
		m_a = 400;
		d = 300;
	}
	int m_a;
	int d;
};

void test()
{
	son s;
	cout<<"sizeof(s):"<<sizeof(s)<<endl;
	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()
{
	test();
	system("pause");
	return 0;
}
总结:多继承下访问父类继承下来同名要加作用域

———————————————————————————————————
菱形继承
形成条件:

1.两个派生类继承一个基类
2.一个类再继承两个派生类
这个就叫做菱形继承,也叫做钻石继承

问题:此时这个类便产生了两义性

解决:
1.在继承之前加virtual,此时父类又称为虚基类
2.此时可以直接访问这个类的成员属性

例子:

#include <iostream>
#include <string>
using namespace std;
class animal
{
public:

	int m_age;
};

class sheep:virtual public animal {};  //下面两个派生类继承一个基类

class tuo:virtual public animal {};

class sheeptuo:public sheep,public tuo {};//一个类再继承两个派生类,此时便有了二义性,有两个m_age

void test01()
{
	sheeptuo st;
	st.sheep::m_age = 18;
	st.tuo::m_age = 15;  //哪个最后更改数值,就为哪个,并且两个继承类的属性都会更改
	
	cout<<"羊的年龄为:"<<st.sheep::m_age<<endl;
	cout<<"驼的年龄为:"<<st.tuo::m_age<<endl;
	cout<<"羊驼的年龄为:"<<st.m_age<<endl;    //继承之前加上virtual 便可以直接进行访问
}
int main()
{
	test01();
	system("pause");
	return 0;
}

运行程序:三个年龄都为15,是按照最后赋值的结果来进行指向的。

                                                       时间:2020.1.14-15
发布了8 篇原创文章 · 获赞 2 · 访问量 159

猜你喜欢

转载自blog.csdn.net/cl939974883/article/details/103979663