【C++课程学习】:继承(上)(详细讲解)

时间:2024-11-09 21:17:43

????个人主页:我们的五年

????系列专栏:C++课程学习

????欢迎大家点赞????评论????收藏⭐文章

 

目录

一.继承的概念和定义

????继承的概念:

????继承的定义:

基本概念:

基本格式:

????继承基类成员访问方式的变化(九种):

二.基类和派生类对象赋值转换

三.继承中的作用域

????隐藏:


 

一.继承的概念和定义

????继承的概念:

继承是面向对象程序设计使代码可以复用的重要手段,它允许在原有类的基础上进行拓展,增加功能,形成新的类。

继承体现了面向对象程序设计的层次结构。继承是类设计层级的复用。

????继承的定义:

//基类(父类)
class person {
private:
	string _name;
};

//派生类(子类)
class student:public person
{
	//子类拓展的内容
};

基本概念:

由????1.派生类(子类),????2.基类(父类),????3.继承方式(可省略),构成。

子类:子类也可叫做派生类,是在继承父类(基类)以后生成的新类。

父类:原来的基础类。

继承方式:以哪种方式进行继承,继承的方式有三种:public,protected,private。

当不写的时候:

1.派生类是class,那么继承方式就是private(私有继承)。

2.派生类是struct,继承方式就是public(公有继承)。

基本格式:

下面的student是派生类,继承方式是:public(共有继承),基类是person。

????继承基类成员访问方式的变化(九种):

 

⏰1.规律:基类的private(私有)都是不可见,其他的:在派生类的访问方式=min(在基类的访问方式,继承方式)。

public>protected>private。

例如,基类的public成员,以private继承,在基类的访问方式=min(public,private)=private。

⏰2.基类的private成员无论以哪种方式继承,在派生类中都是不可见的。这里的不可见是指,虽然在派生类中继承下来,但是在派生类里,还是在类外面都是不能访问。

⏰3.如果基类的成员想被子类访问,不想被类外访问,那么把基类的成员定义为protected就可以了。也就是说,protected是在继承才出现的,在其他的地方,protected和private基本差不多。

⏰4.当不写的时候:(实际中还是写出继承方式比较好)

1.派生类是class,那么继承方式就是private(私有继承)。

2.派生类是struct,继承方式就是public(公有继承)。

⏰5.在实际中,一般的继承方式都是public,因为其他两种继承,会把基类的访问方式缩小。这个子类去生成新的子类的时候,拓展性就不高了。

二.基类和派生类对象赋值转换

●派生类对象可以赋值给基类的对象 / 基类的指针 / 基类的引用。这里可以看成切片或者切隔,还是指向派生类的。

●基类对象不能赋值给派生类对象。

●基类的指针和引用可以强制类型转化赋值给派生类的指针或者引用。但是必须是基类的指针或者引用是指向派生类才是安全的。

class person
{
protected:
	string _name; // 姓名
	string _sex; // 性别
	int _age; // 年龄
};

class student : public person
{
public:
	int _No; // 学号
};

void Test()
{
	student st;
	// 1.子类对象可以赋值给父类对象/指针/引用
	person p = st;
	person* pp = &st;
	person& rp = st;

	//2.基类对象不能赋值给派生类对象
	//sobj = p;

	// 3.基类的指针可以通过强制类型转换赋值给派生类的指针
	pp = &st;
	student* ps1 = (student*)pp;	// 这种情况转换时可以的。
	ps1->_No = 10;

	pp = &p;
	student* ps2 = (student*)pp; // 这种情况转换时虽然可以,但是会存在越界访问的问题
	ps2->_No = 10;
}

 下面最后一种情况时,pp先取一个student的地址,然后再强制类型转换给一个student类型的ps1,然后通过ps1去访问_No,不会发生越界。如果先取的也是person类型的地址,就会发生越界。

我的理解是,C++允许子类的指针给父类的指针,上面不越界的情况,是原来他是属于student,除person外那块空间可能进行特殊处理,表示如果再次转换回student就不会报错。

void test()
{
	student st;
	st._No = 123;

	person* pp = &st;
	student* ps1 = (student*)pp;	
	cout << ps1->_No << endl;
}

三.继承中的作用域

目前我学过的域有:全局域,类域,局部域,命名空间域。

在同一域中:

●不能有相同的变量名,即使他们的类型不同。

●可以有同名函数存在,但是参数列表不同,他们构成重载。

在两个域中:

●可以有相同的变量名。

●可以有函数原型相同的函数。


●在父类和子类中,他们两个都是单独的作用域

●在父类和子类中(一个函数在父类,一个函数在子类),可以有函数原型一样的函数,他们构成隐藏。也叫重定义。


????隐藏:

????隐藏的概念:

子类屏蔽对父类同名函数的访问,如果要访问,需要在函数前面写父类,表示在父类去找。

不然如果你想用父类的那个同名函数,如果不显示指定,子类的对象调用时,编译器只会在子类中找,不会因为不匹配,而去父类找,如果不匹配,直接编译不通过。

基类::基类成员        进行显示访问!

class A
{
public:
	void fun()
	{
		cout << "func()" << endl;
	}
};
class B : public A
{
public:
	void fun(int i)
	{
		A::fun();
		cout << "func(int i)->" << i << endl;
	}
};

void test()
{
	B b;
	b.fun();    //没有指定类域,编译器只会在子类中找,不匹配直接编译出错
    b.A::fun();
}

 

●在父类和子类中,只要两个函数的函数名相同就构成隐藏。

●在实际中,不建议在父类,子类写同名的函数。