私有继承:使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员,只可以在派生类的成员函数中使用
一、私有继承示例
class Student : private std::string,private std::valarray<double>
{
public:
...
}
//student以私有继承的方式继承了string类和valarray类
//stduent是多重继承(使用多个基类的继承被称为多重继承)
示例student类
class Student
{
private:
typedef std::valarray<double> ArrayDb;//可以在student类的实现中使用,类外不可以
std::string name;
ArrayDb scores;
std::ostream & arr_out(std::ostream & os) const;
public:
Student(): name("NULL Student"),scores() {}
//explicit 防止单参数的构造函数的隐式转换
explicit Student(const std::string & s) : name(s),scores() {} //explicit 表示该构造函数是显示的,只能修饰一个参数的构造函数
explicit Student(int n) : name("Nully"),scores(n) {}
Student (const std::string & s,int n) : name(s),scores(n) {}
Student (const std::string & s,const ArrayDb & a) : name(s),scores(a) {}
Student (const char * str,const double * pd,int n) : name(str),scores(pd,n) {}
~Student() {}
double Average() const;
const std::string & Name() const;
double & operator[](int i);
double operator[](int i) const;
friend std::istream & operator>>(std::istream & is,Student & stu);//重载输入
friend std::istream & getline(std::istream & is,Student & stu);
friend std::ostream & operator<<(std::ostream & os,const Student & stu);//重载输出
};
1.初始化类的区别
公有继承的构造函数初始化
Student(const char *str,const double *pd,int n) : name(str),scores(pd,n){}
私有继承的构造函数初始化
Student(const char * str,const double *pd,int n) :std::string(str),ArrayDb(pd,n){}
[注]:1.私有继承使用成员初始化列表方法时,使用类名而不是成员名来初始化标识构造函数。
2.在私有继承中,在不进行显示类型转换的情况下,不能将指向派生类的引用或者指针赋给基类引用或指针。
2.私有继承demon
#include
#include
#include
using std::ostream;
using std::endl;
using std::istream;
using std::string;
class Student : private std::string, private std::valarray<double>
{
private:
typedef std::valarray<double> ArrayDb;//可以在student类的实现中使用,类外不可以
std::ostream & arr_out(std::ostream & os) const;
public:
Student() : std::string("Null student"),ArrayDb() {}
explicit Student(const std::string & s) : std::string(s),ArrayDb() {}
explicit Student(int n) : std::string("Nully"),ArrayDb(n) {}
Student(const std::string & s,int n) : std::string(s),ArrayDb(n) {}
Student(const char *str,const double *pd,int n) : std::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);
friend std::istream & getline(std::istream & is,Student & stu);
friend std::ostream & operator<<(std::ostream & os,const Student & stu);
};
//类的实现
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);
}
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 & getline(istream & is,Student & stu)
{
getline(is,(string &)stu);
return is;
}
ostream & operator<<(ostream & os,const Student & stu)
{
os << (const string &)stu <<"同学的成绩:\n";
stu.arr_out(os);
return os;
}
using std::cin;
using std::cout;
void set(Student & sa,int n);
const int pupils = 3;
const int quizzes = 5;
int main()
{
Student ada[pupils] = { Student(quizzes),Student(quizzes),Student(quizzes)};
int i;
for (i = 0;i < pupils; ++i)
set(ada[i],quizzes);
cout<< "\n Studnet List:\n";
for(i = 0; i < pupils; ++i)
cout << ada[i].Name() << endl;
cout << "\n 学生信息:";
for(i = 0; i < pupils; i++)
{
cout << ada[i] <<endl;
cout << "平均成绩:" << ada[i].Average() << endl;
}
cout << " Done\n" << endl;
return 0;
}
void set(Student & sa,int n)
{
cout << "请输入学生名:";
getline(cin,sa);
cout << "请输入学 " << n <<"项成绩:\n";
for(int i = 0; i < n; i++)
cin >> sa[i]; //因为对 & [] 进行了重载,所以这里可以将成绩输入到socres数组中
while(cin.get() != '\n')
continue;
}
#include
#include
#include
class Student
{
private:
typedef std::valarray<double> ArrayDb;//可以在student类的实现中使用,类外不可以
std::string name;
ArrayDb scores;
std::ostream & arr_out(std::ostream & os) const;
public:
Student(): name("NULL Student"),scores() {}
//explicit 防止单参数的构造函数的隐式转换
explicit Student(const std::string & s) : name(s),scores() {} //explicit 表示该构造函数是显示的,只能修饰一个参数的构造函数
explicit Student(int n) : name("Nully"),scores(n) {}
Student (const std::string & s,int n) : name(s),scores(n) {}
Student (const std::string & s,const ArrayDb & a) : name(s),scores(a) {}
Student (const char * str,const double * pd,int n) : name(str),scores(pd,n) {}
~Student() {}
double Average() const;
const std::string & Name() const;
double & operator[](int i);
double operator[](int i) const;
friend std::istream & operator>>(std::istream & is,Student & stu);//重载输入
friend std::istream & getline(std::istream & is,Student & stu);
friend std::ostream & operator<<(std::ostream & os,const Student & stu);//重载输出
};
//类的实现
using std::ostream;
using std::endl;
using std::istream;
using std::string;
//平均分
double Student::Average() const
{
if(scores.size() > 0)
return scores.sum()/scores.size();
else
return 0;
}
const string & Student::Name() const
{
return name;
}
double & Student::operator[](int i)
{
return scores[i];
}
double Student::operator[](int i) const
{
return scores[i];
}
//私有类函数方法,调整打印格式
ostream & Student::arr_out(ostream & os) const
{
int i;
int lim = scores.size();
if(lim > 0)
{
for(i = 0; i < lim; i++)
{
os << scores[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 >> stu.name;
return is;
}
istream & getline(istream & is,Student & stu)
{
getline(is,stu.name);
return is;
}
ostream & operator<<(ostream & os,const Student & stu)
{
os << " Scores for " << stu.name << " :\n";
stu.arr_out(os);
return os;
}
using std::cin;
using std::cout;
void set(Student & sa,int n);
const int pupils = 3;
const int quizzes = 5;
int main()
{
Student ada[pupils] = { Student(quizzes),Student(quizzes),Student(quizzes)};
int i;
for (i = 0;i < pupils; ++i)
set(ada[i],quizzes);
cout<< "\n Studnet List:\n";
for(i = 0; i < pupils; ++i)
cout << ada[i].Name() << endl;
cout << "\n 学生信息:";
for(i = 0; i < pupils; ++i)
{
cout << ada[i] <<endl;
cout << "平均成绩:" << ada[i].Average() << endl;
}
cout << " Done\n" << endl;
return 0;
}
void set(Student & sa,int n)
{
cout << "请输入学生名:";
getline(cin,sa);
cout << "请输入学 " << n <<"项成绩:\n";
for(int i = 0; i < n; i++)
cin >> sa[i]; //因为对 [] 进行了重载,所以这里可以将成绩输入到socres数组中
while(cin.get() != '\n')
continue;
}
二、保护继承
保护继承:保护继承是私有继承的变体,保护继承在列出基类时使用关键字protected
class Student : protected std::string,protected std::valarray<double>
{...};
//保护继承时,基类的公有成员都将变成派生类的保护成员。和私有继承一样,基类的接口在派生类中也可用,继承层次之外不可用。
//在派生类中,保护继承无需显示类型转换,就可以将基类的指针或引用指向派生类对象。
三、使用using重新定义访问权限
实现:使用派生或私有派生时,基类的公有成员将成为保护成员或私有成员。实现基类的方法在派生类中可用,可以定义一个使用该基类方法的派生类方法。
法一:定义一个使用该基类方法的派生类方法
double Student::sum() const
{
return std::valarry<double>::sum();
}
法二:将函数调用包装在另一个函数调用中,即使用一个using声明来指出派生类可以使用特定的基类成员,即使用的是私有派生
class Student : private std::string,private std::valarray<double>
{
...
public:
using std::valarray<double>::min;
using std::valarray<double>::max;
...
};
//使用
cout << "high score: " << ada[i].max() << endl;
[注]:1.using声明只使用成员名——没有圆括号、函数特征标和返回类型。
2.using声明只适用于继承,不适用于包含
法三:将方法名放在派生类的公有部分
class Student : private std::string,private std::valarry<double>
{
...
public:
std::valarry<double>::operator[];//redeclare as public,just use name
}
//法三需要编译器的支持,因为此方法即将摒弃