私有继承

私有继承

公有继承实现is-a模型,私有继承实现has-a模型.

私有继承将基类的公有成员和保护成员继承成为派生类的私有成员,这意味着派生类对象不能使用私有函数,但是在派生类域内也能使用私有成员.

包含将对象作为一个命名的成员对象添加到类中,私有继承将对象作为一个未被命名的继承对象添加到类中,称为子对象.这是和包含的第一个区别.

这样私有继承就完成了has-a模型的实现.

私有继承和包含的区别

私有继承格式如下:

class Student : private string,private valarray<double>
{
	public:
	...
}

由于使用子对象来描述私有对象继承的对象,子对象是没有名字的,之前包含采用初始化列表初始化对象:

Student(const char * str, const double * pd, int n)
    					: name(str), scores(pd, n) {}

由于私有继承没有对象名字,所以类名隐式调用构造函数:

Student(const char * str, const double * pd, int n)
   					 : string(str), ArrayDb(pd, n) {}

这是和包含的第二个区别.

利用私有继承实现Student类

类声明如下:

class Student : string, valarray<double>		// 采用了多重继承,这个例子不会发生冲突
{
private:
    typedef valarray<double> ArrayDb;
    // 私有的输出函数
    std::ostream & arr_out(std::ostream & os) const;
public:
    Student() : string("Null Student"), ArrayDb() {}
    
    /  		*****************************		/
    *		由于采用了私有继承,继承了没			*
    *		有名字的对象,直接用类名进行			*
    *		隐式初始化								*
   /  		*****************************			/
    
    explicit Student(string & s)		
	    : string(s), ArrayDb() {}
    explicit Student(int n) : string("Nully"), ArrayDb(n) {}
    Student(string & s, int n)
	    : string(s), ArrayDb(n) {}
    Student(string & s, const ArrayDb & a)
	    : string(s), ArrayDb(a) {}
    Student(const char * str, const double * pd, int n)
	    : string(str), ArrayDb(pd, n) {}
	    
	    
    ~Student() {}
    double Average() const;
    double & operator[](int i);
    double operator[](int i) const;
    const std::string & Name() const;
    
    // 友元输入函数
    friend std::istream & operator>>(std::istream & is,
	                             Student & stu);  // 1 word
    friend std::istream & getline(std::istream & is,
	                          Student & stu);     // 1 line
    // 友元输出函数
    friend std::ostream & operator<<(std::ostream & os,
	                             const Student & stu);
};

通过域解析运算符来解决访问基类函数的方法:

包含所用的方法:

double Student::Average() const
	{
	    if (ArrayDb::size() > 0)
		return scores.sum()/scores.size();
	    else
		return 0;
	}

私有继承所用的方法:

double Student::Average() const
	{
	    if (ArrayDb::size() > 0)
		return ArrayDb::sum()/ArrayDb::size();		// 利用类和域运算符来调用类方法
	    else
		return 0;
	}

访问基类对象:

由于Student类是从string类派生而来的,可以使用枪支转换,转换为基类对象,为了避免创造新的对象,所以,强制转换为const string&引用类型,如下:

const string & Student::Name() const
	{
	    return (const string &) *this;		//	*this代表调用函数的对象
	}

通过类名和作用域解析运算符调用基类的友元函数不合适,因为友元函数不属于类函数,然而,可以显式转换为基类,在正确调用基类的友元函数.

ostream & operator<<(ostream & os, const Student & stu)
	{
	    os << "Scores for " << (const string &) stu  << ":\n";
	    stu.arr_out(os);  // use private method for scores
	    return os;
	}

将Student对象转换为基类string的对象,通过调用基类的operator<<(ostream & , const string &).

私有继承中,没有进行显式的强制转换的派生类和指针,无法赋值给基类引用和指针.

就算是公有继承,也必须是显示转换,因为os<<stu与自己匹配,将递归调用自己.

Student类函数如下:

double Student::Average() const
	{
	    if (ArrayDb::size() > 0)
		return ArrayDb::sum()/ArrayDb::size();
	    else
		return 0;
	}

	const string & Student::Name() const
	{
	    return (const string &) *this;
	}

	double & Student::operator[](int i)
	{
	    return ArrayDb::operator[](i);         // 使用ArrayDb::operator[]()类函数
	}

	double Student::operator[](int i) const
	{
	    return ArrayDb::operator[](i);		// 同上
	}

	// 私有函数,通过循环打印每一个数组元素
	ostream & Student::arr_out(ostream & os) const
	{
	    int i;
	    int lim = ArrayDb::size();
	    if (lim > 0)
	    {
		for (i = 0; i < lim; i++)
		{
		    os << ArrayDb::operator[](i) << " ";
		    if (i % 5 == 4)
			os << endl;
		}
		if (i % 5 != 0)
		    os << endl;
	    }
	    else
		os << " empty array ";
	    return os;
	}

	// 友元输入函数,输入姓名
	istream & operator>>(istream & is, Student & stu)
	{
	    is >> (string &)stu;
	    return is;
	}

	// 使用string友元函数getline(ostream &, const string &)
	istream & getline(istream & is, Student & stu)
	{
	    getline(is, (string &)stu);
	    return is;
	}

	// 有元输出姓名和成绩
	ostream & operator<<(ostream & os, const Student & stu)
	{
	    os << "Scores for " << (const string &) stu  << ":\n";
	    stu.arr_out(os);  // use private method for scores
	    return os;
	}

测试函数如下:

void set(Student & sa, int n);		// 声明一个输入类姓名和成绩的函数
	const int pupils = 3;		// Student对象个数
	const int quizzes = 5;		// 有多少门成绩

	int main()
	{
	    Student ada[pupils] =
		{Student(quizzes), Student(quizzes), Student(quizzes)};

	    int i;
	    for (i = 0; i < pupils; ++i)		// 给三个Student对象赋值
		set(ada[i], quizzes);
	    cout << "\nStudent List:\n";
	    for (i = 0; i < pupils; ++i)		// 打印出三个Student类的名字
		cout << ada[i].Name() << endl;
	    cout << "\nResults:";
	    for (i = 0; i < pupils; ++i)		// 完整打印出每个对象的成绩和平均成绩
	    {
		cout << endl << ada[i];
		cout << "average: " << ada[i].Average() << endl;
	    }
	    cout << "Done.\n";
	    // cin.get();

	    return 0;
	}

	void set(Student & sa, int n)
	{
	    cout << "Please enter the student's name: ";
	    getline(cin, sa);
	    cout << "Please enter " << n << " quiz scores:\n";
	    for (int i = 0; i < n; i++)
		cin >> sa[i];		// 调用double& operator[](int i)函数,可以作为输入值
	    while (cin.get() != '\n')
		continue;
	}

结果如下:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值