【C++】—— C++中的继承(上)

继承与派生

继承关系和访问限定符

三种访问限定符:public protected private
三种继承关系:public protected private

继承基类成员访问关系的变化
访问关系
总结

  1. 基类(父类)private成员在派生类中无论以什么方式继承在派生类(子类)都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它
  2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
  3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。
  4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式

基类和派生类的赋值转换

  • 派生类对象可以赋值给 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割。寓意把派生类中父类那部分切来赋值过去。
  • 基类对象不能赋值给派生类对象。
  • 基类的指针可以通过强制类型转换赋值给派生类的指针。但是必须是基类的指针是指向派生类对象时才是安全的。

这里我们来举个栗子

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;

//基类和派生;类对象的赋值转换

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

class Student : public Person
{
public:
	int Num;//学号
};

int main()
{
	Person p;
	Student s;
	p = s;//将子类对象传给父类,切割或是切片,允许
	Person* pp = &s;//将子类对象的地址传给父类指针,允许
	Person& rp = s;//将子类对象传给父类的引用,允许
	//s = p; //将父类对象传给子类,不允许
	Student* ps1 = (Student*)pp;//将父类指针强制类型转换为子类指针,允许

	//此时ps1指向的是子类对象,用ps1访问子类对象中的成员Num,不会越界
	ps1->Num = 10;


	pp = &p;
	Student* ps2 = (Student*)pp;
	//此时ps2指向的是基类对象,用ps2访问派生类类对象中的成员Num,会越界
	ps1->Num = 20;
	return 0;
}

基类与派生类对象的赋值转换

继承中的作用域

  1. 在继承体系中基类和派生类都有独立的作用域
  2. 子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义(在子类成员函数中,可以使用 基类::基类成员 显示访问)
  3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
  4. 注意在实际中在继承体系里面最好不要定义同名的成员。

来举个栗子看看

//继承中的作用域
// B中的fun和A中的fun不是构成重载,因为不是在同一作用域
// B中的fun和A中的fun构成隐藏,成员函数满足函数名相同就构成隐藏。
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()
{
	A a;
	B b;
	a.fun();
	b.fun();//此时编译不通过,因为派生类与基类的函数名相同构成隐藏,此时派生类无法调用基类的fun函数
	b.A::fun();//显示指定是允许
	b.fun(10);
};

int main()
{
	Test();
	return 0;
}
函数重载与函数重定义
  • 构成函数重载的函数必须在同一个作用域中,且函数名相同
  • 构成函数重定义在不同作用域,一个在基类一个在派生类,函数名也相同

这里有一个需要注意的点,就是基类的析构函数与派生类的析构函数也会构成隐藏

举个栗子说明一下

#include <iostream>
#include <string>
using namespace std;

class Person
{
public:
	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name;
	int _age;
};
class Student
{
public:
	~Student()
	{
		cout << "~Student()" << endl;
	}
private:
	int _Num;
};

int main()
{
	Student s;
}

析构函数的重定义

  • 这里我们可以看到,在我们创建了一个派生类成员之后,销毁时该对象只调用了派生类的析构函数并未调用基类析构函数,是因为这里基类析构函数与派生类析构函数构成了隐藏,此时派生类对象无法调用基类的析构函数了。
  • 很多人可能会说只有函数名,返回值,参数都相同的函数才会构成隐藏吗?很明显这基类与派生类的两个析构函数的函数名都不相同,为什么会构成隐藏呢?
  • 其实这里是因为在底层编译器会将析构函数都处理为名为distructor()的函数,这时,基类和派生类的析构函数的函数名就相同了,又因为析构函数没有返回值和参数,因此构成了隐藏。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值