Fork me on GitHub

C++:类的私有继承、公有继承、多重继承讨论

背景

第十四章课后练习第一题中,再次提及了私有继承、公有继承和多重继承。想了想好像这块儿的概念有点淡忘,感觉比较重要,特意写个小结。果然C++的越来越多的关键字很被人厌烦是有道理的啊,不经常使用的话好容易忘记。

公有继承

/*抽象基类*/
class worker
{
protected:
	virtual void data() const;
	virtual void get();
private:
	string fullname;
	long id;
public:
	worker() : fullname("none"), id(0) {};
	worker(const string& fn, long n) : fullname(fn), id(n) {};
	virtual ~worker() {};
	virtual void set() = 0;/*抽象基类定义为纯需函数,不进行实例化    */
	virtual void show() const = 0;
};

/*worker派生类*/
class waiter :public virtual worker//虚基类,这样singer就只继承了一个worker
{
protected:
	virtual void data() const;
	virtual void get();
private:
	int panache;
public:
	waiter() : worker(), panache() {};
	waiter(const string& fn, long n, int p) : worker(fn,n), panache(p) {};
	waiter(const worker& wk, int p = 0) :worker(wk), panache(p) {};
	virtual ~waiter() {};
	virtual void set();/*继承来的,不定义virtual也行*/
	virtual void show() const;/*继承来的,不定义virtual也行*/
};

这串代码中就体现了公有继承public,当然继承的对象是一个虚基类(虚基类和非虚基类的区别就是在mian中定义派生类否会产生多个基类对象的区别)。继续谈公有继承,公有继承顾名思义就是继承基类的公有接口,比如上述代码中water派生类会继承set()show()public:声明中的其他接口,因此获得了实现,也获得了接口。还有比较有意思的一点是,一个基类支持派生出多个公有派生类,但是需要声明为虚(原因已经说明)。

私有继承

/*私有继承+多重继承*/
class student : private string,private valarray<double>
{
private:

	typedef valarray <double> ArrayDB; //放到类里面,为了限制ArrayDB不能被外部调用
	string name;//string类过来的,也就是多重继承,name也可以用string类的方法
	ArrayDB scores;//valarray类,多重继承,scores也可以用valarray类的方法
	/*添加一个接口用来调用私有基类的size方法*/
	ostream &arr_out(ostream & os) const;

public:
	/*此时string是一个未命名类,需要调用string类的构造函数进行初始化*/
	student() : string("none student")/*调用string的构造函数*/, ArrayDB()/*调用valarray的构造函数*/ {};//初始化列表
	/*传递一个整数的定义array有n各对象的*/
	student(const string& s, int n) :string(s), ArrayDB(n) {};
	/*传递一个valarray的*/
	student(const string& s, const ArrayDB& a) :string(s), ArrayDB(a) {};
	student(const string& s, const double* pd, int n) :string(s), ArrayDB(pd/*成员定义*/, n/*成员数量*/) {};

	~student() {};

	/*方法*/
	double average() const;//统计平均成绩
	const string& Name() const;//返回name
	double& operator[](const int n/*数组的编号*/);//操作成员,可以修改

	friend istream& operator>>(istream& is, student& st);
	friend ostream& operator<<(ostream& os, student& st);
	friend istream& getline(istream& is, student& st);

	/*显式转换 将string类对象转为student类对象 同时初始化其他参数*/
	explicit student(const string& s) : string(s), ArrayDB() {};
	/*显式转换 */
	explicit student(const int n) : string("none student"), ArrayDB(n) {};

};

 私有继承相对来说更私密一些,怎末说呢?就是私有继承会将基类的公有方法变为派生类的私有方法,也就是说派生类定义一个类对象后,想在类对象中访问私有基类的公有接口,必须使用派生类的共有接口(此接口包含了私有基类的方法并且是通过作用域解析运算符::和强制类型转换(cosnt string) student来实现),不能够直接像公有继承一样直接在定义一个对象后直接访问私有基类的公有接口了。所以私有继承其实也能通过某种手段去访问基类的接口,但是这就违背了私有继承的本意了。总之,私有继承也就是获得实现,但不获得接口,这一点和包含关系一样。

多重继承

呐~一个派生类继承了多个基类方法的现象叫做多重继承。woker是虚基类,singer和waiter是虚基类的派生类,采用公有继承。而singerwaiter是将singer和waiter作为基类的派生类,也就是多重继承。

总结

  • 包含:获得实现,也获得接口,可以是多种类对象
  • 私有继承:获得实现、不获得接口;但是只能是一种类对象
  • 公有继承:获得实现、也获得接口
  • 多重继承:获得所有基类的实现,但不一定获得接口

回到背景原因,我们什么时候使用私有继承、什么时候使用公有继承呢?就本白现在的理解,当基类的方法和对象全部都使用于派生类时,使用公有继承,这样随便访问都不会出现访问错误的现象;当基类的方法和对象并不完全适用于派生类时,应考虑私有继承,因为你不想让派生类访问一些基类的不适用成员。

posted @ 2022-12-11 19:39  张一默  阅读(142)  评论(0编辑  收藏  举报