C++中的继承详解

继承、派生类、基类

1.概念说明

继承:从先辈处得到
继承:从先辈处得到属性和行为特征,类的继承就是新的类从已有的类那里得到已有的特性。
基类:已有的类称为基类,也称为父类。
派生类:新的类称为派生类,也成为子类。
派生类同样也可以作为基类派生出新的类。

1.1类的继承方式的分类

1.公有继承(public)
2.保护继承(protected)
3.私有继承(private)
如果不显式给出继承方式关键字,则默认为私有继承(private)

2.派生类与基类的声明与构成

2.1声明

class Person//基类(父类)
{
private:
	string Name;
public:
	Person(string name) : Name(name)
	{

	}
	void Print()
	{
		cout << "Name:" << Name << endl;
	}
};
//派生类(子类)//公有继承
class Studet :public Person
{
private:
	string sex;	//新增加的数据成员
public:
	Studet(string ssex,string name):sex(ssex),Person(name)
	{

	}
	void Show()		//新增加的成员函数
	{
		cout << "sex:" << sex << endl;
	}
};

从上面代码中,我们分析得到"class Studet"之后,跟着":public Person",这意味着类Student继承了类Person。
其中类Person是基类,类Student是派生类。
关键字public指出基类Person中的成员在派生类Student中的继承方式(公有继承)。

由此可见,设计一个派生类的一般格式为:
class 派生类名称:[继承方式] 基类名称
{
派生类的数据成员和成员函数
};
"基类名称"是一个已经声明的类的名称
"派生类名称"是基础基类的特性而生成的新类的名称。
"继承方式"是前面所说的三种继承方式之一。

2.2构成

基类Person和派生类Student的关系在这里插入图片描述

3.派生类与基类的构造与析构过程

class Object
{
private:
	int value;
public:
	Object(int x = 0) :value(x)
	{
		cout << "Create Object: " << this << endl;
	}
	~Object()
	{
		cout << "Destory Object: " << this << endl;
	}
};
class Test :public Object//先构建父对象,再构建子对象;先析构子对象,再析构父对象
{
public:
	typedef Object _Base;
private:
	int num;
public:
	Test(int x = 0) :num(x), Object(x + 10)//_Base(x)
	{
		cout << "Create Test: " << this << endl;
	}
	~Test()
	{
		cout << "Destory Test: " << this << endl;
	}
};

int main()
{
	Test t1(10);

	return 0;
}

从上述代码,我们可以得到:
(1)在构造过程中,先构建父对象,再构建子对象;
(2)在析构过程中,先析构子对象,再析构父对象
下面我们看一下这两个过程
在这里插入图片描述

4.派生类与基类所占字节数

class Object
{
private:
	int value;
public:
	Object(int x = 0) :value(x)
	{
		cout << "Create Object: " << this << endl;
	}
	~Object()
	{
		cout << "Destory Object: " << this << endl;
	}
};
class Test :public Object
{
public:
	typedef Object _Base;
private:
	int num;
public:
	Test(int x = 0) :num(x), Object(x + 10)//_Base(x)
	{
		cout << "Create Test: " << this << endl;
	}
	~Test()
	{
		cout << "Destory Test: " << this << endl;
	}
};

int main()
{
	Object obj(10);
	Test t1(10);

	cout << "sizeof(Obj):" << sizeof(obj) << endl;
	cout << "sizeof(t1):" << sizeof(t1) << endl;

	return 0;
}

在这里插入图片描述
Obj和t1的具体构造在这里插入图片描述
在这里插入图片描述

派生类对基类成员的访问规则

值得注意的是:可访问性:指的是对象的可访问性

1.三种继承的访问规则

不管是那种继承,我们都可以访问基类的public和protected成员,而private成员不可访问

class Object
{
private:	int oa;
protected:	int ob;
public:		int oc;
};
class BasePublic :public Object
{
public:
	void set()
	{
		//可以访问继承里面的公有和保护,不能访问继承里面的私有
		Object::ob = 10;
		Object::oc = 20;
	}
};
class BaseProtected :protected Object
{
public:
	void set()
	{
		//可以访问继承里面的公有和保护,不能访问继承里面的私有
		Object::ob = 200;
		Object::oc = 300;
	}
};
class BasePrivate :private Object
{
public:
	void set()
	{
		//可以访问继承里面的公有和保护,不能访问继承里面的私有
		Object::ob = 20;
		Object::oc = 30;
	}
};

2.成员对象和继承来的对象的访问区别

不管是那种继承:
都可以访问成员对象里面的公有,不能访问成员对象里面的保护和私有
都可以访问继承里面的公有和保护,不能访问继承里面的私有

class Object
{
private:	int oa;
protected:	int ob;
public:		int oc;
};
class BasePublic :public Object
{
public:
	Object obj;//对象
public:
	void set()
	{
		//可以访问成员对象里面的公有,不能访问成员对象里面的保护和私有
		//obj.oa = 10;//error
		//obj.ob = 10;//error
		obj.oc = 10;
		//可以访问继承里面的公有和保护,不能访问继承里面的私有
		//Object::oa = 10;//error
		Object::ob = 20;
		Object::oc = 30;
	}
};

派生类的应用

1.赋值兼容规则和切片现象

赋值兼容规则只适合于公有派生
class Person
{
private:
	int value;
public:
	Person(int x = 0) :value(x)	{	}
};
class Student :public Person
{
private:	int num;
public:		
	Student(int x = 0) :num(x), Person(x + 10)	{	}
};
void dance(const Person& s){     }
void Study(const Student& s){    }
int main()
{
	Person se(23);
	Student st(10);

	Person& sp = st;//引用
	Person* p = &st;
	se = st;

	dance(se);
	dance(st);
	Study(st);
	//Study(se);//error

	return 0;
}

下面,我们分析一下具体过程
执行Person se(23);
Student st(10);时:
在这里插入图片描述

执行Person& sp = st;//引用
Person* p = &st;
在这里插入图片描述

执行se = st;
当把子对象给父对象(前提条件是公有继承),发生了切片现象。
在这里插入图片描述

通过上面的代码分析我们可以得到:
(1)派生类对象可以向基类对象赋值;
(2)派生类对象可以初始化基类对象的引用

2. 同名隐藏

2.1数据成员的同名隐藏

下面以代码为例说明

class Object
{
public:
	int value;
public:
	Object(int x = 0) :value(x)	{	}
	void Print()
	{
		cout << "Object:value: " << value << endl;
	}
};
class Base :public Object
{
public:
	int value;
public:
	Base(int x = 0) :Object(x), value(x + 10)	{	}
	void Set()
	{
		value = 100;//Base里面的value(就近原则),把父对象的value隐藏了
		//Object::value = 10;//value是protected或者pubic
		//同名隐藏
	}
	void Show()
	{
		cout << "Base:value: " << value << endl;
	}
};
int main()
{
	Object obj(1);
	Base ba(2);

	obj.Print();
	ba.Show();
	ba.Print();

    ba.Set();
	ba.Show();
	ba.Print();

	return 0;
}

在这里插入图片描述

2.2成员函数的同名隐藏

同样,我们以代码为例说明

子对象调动时会隐藏父对象的同名函数

class Object
{
public:
protected:
	int value;
public:
	Object(int x = 0) :value(x)	{	}
	void Print(int x =0)
	{
		value = x;
		cout <<"Object:value: " <<value << endl;
	}
	void Show()
	{
		cout << "Object:value: " << value << endl;
	}
};
class Base :public Object
{
public:
	int num;
public:
	Base(int x = 0) :Object(x), num(x + 10)	{	}
	void Print()const
	{
		cout <<"hello !"<< endl;
	}
};
int main()
{
	Base base1(10);
	Object obj1(100);

	base1.Print();//子对象的
	base1.Object::Print();//父对象的方法

	//base1.Print(10);//error
	//子对象调动时会隐藏父对象的同名函数,不是重载的意义
	base1.Object::Print(80);//OK
	
	base1.Show();

	obj1.Show();
	
	return 0;
}

在这里插入图片描述

END!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值