//第十四章 代码重用
1. 公有继承(public)
公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,
不能被这个派生类的子类所访问。
2. 私有继承(private)
私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。
3. 保护继承(protected)
保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,
基类的私有成员仍然是私有的。
一.私有继承
1.介绍私有继承前先介绍包含对象成员的类
class Student
{
private:
std::string name;//包含对象成员
std::valarray<double> scores;
public:
...
};
2.私有继承
class Student : private std::string, private std::valarray<double>//Student私有继承string类,valarray类
{
private:
typedef std::valarray<double> Array;//不能声明类成员,比如string name;
std::ostream & arr_out(std::ostream & os)const;
public:
Student():string("Null Student"),Array(){}
Student(const string & s):string(s),Array(){}
Student(const string & s,int n):string(s),Array(n){}
Student(const string & s,const Array & a):string(s),Array(a){}
~Student(){}
double Average()const;
const string & Name()const;
double & operator[](int n);
double operator[](int n)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);
};
//public method:注意注释部分,比较与包含类成员的方法实现的不同点
std::ostream & Student::arr_out(std::ostream & os)const{
int i;
int lim = Array::size();//按照包含类应该改为scores.size()
if(lim > 0){
for(i = 0;i < lim;i++){
os << Array::operator[](i) << " ";//按照包含类应该改为socres[i];
if(i%5 == 4)
os << std::endl;
}
if(i%5 != 0)
os << std::endl;
}
else
os << " empty array ";
return os;
}
double Student::Average()const{
if(Array::size() > 0)
return Array::sum()/Array::size();//按照包含类应该改为socres.sum()/scores.size()
else
return 0;
}
const string & Student::Name()const{
return (const string &)*this;//这里出入比较大,按照包含类应该改为return name;
}
double & Student::operator[](int i){
return Array::operator[](i);//按照包含类应该改为return socres[i];
}
double Student::operator[](int i)const{
return Array::operator[](i);//按照包含类应该改为return socres[i];
}
std::istream & operator>>(std::istream & is,Student & stu){
is >> (string &)stu;//is >> stu.name;
return is;
}
...
3.虚基类
(1)//为什么要搞出虚基类?看一个例子
//A 作为被继承的基类
class A
{
private:
std::string name;
long id;
protected:
void Data()const;
public:
A():name("Null"),id(0){}
A(const std::string & str,const long s = 0){name = str;id = s;};
~A(){}
virtual void show()const = 0;
};
//A被作用于Singer的虚基类 //关键字 virtual
class Singer:virtual public A
{
private:
std::string stype;
protected:
void Data()const;
public:
Singer():A(),stype("None"){}
Singer(const std::string & tp,const std::string & name = "Null",const long id = 0):A(name,id){stype = tp;}
~Singer(){};
virtual void show()const;
friend std::ostream & operator<<(std::ostream & os,const Singer & sin);
};
//A被作用于Waiter的虚基类 //关键字 virtual
class Waiter:virtual public A
{
private:
int year;
protected:
void Data()const;
public:
Waiter():A(),year(0){}
Waiter(const int sum,const std::string & name = "Null",const long id = 0):A(name,id){year = sum;}
~Waiter(){}
virtual void show()const;
friend std::ostream & operator<<(std::ostream & os,const Waiter & w);
};
//SingerWaiter继承Waiter于Singer
class SingerWaiter:public Waiter,public Singer
{
private:
bool sw;
protected:
void Data()const;
public:
SingerWaiter(){sw = false;};
SingerWaiter(bool t,const std::string & name = "Null",const long id = 0,const int sum = 0,\
const std::string stype = "None"):A(name,id),Waiter(sum,name,id),Singer(stype,name,id){sw = t;}\
~SingerWaiter(){}
virtual void show()const;
friend std::ostream & operator<<(std::ostream & os,const SingerWaiter & swr);
};
//看到这里相信你的心中已经有了答案
//如果不继承虚基类将出现以下问题://即不加关键字virtual
问题(1).Singer继承了A,Waiter继承了A,而SingerWaiter多重继承了Singer与Waiter。。当你定义一个SingerWaiter类的时候,
SingerWaiter ed;
A *pw = &ed;
这将会产生二义性,到底pw指向SInger中的A还是Waiter中的呢?而且明显SingerWaiter类只需要一个A,这里却初始化了两个A。
我们可以这样做解决二义性,A *pw = (Waiter *)&ed;A *pw = (Singer *)&ed
,但是这将使得基类指针的使用复杂化
解决:
class Waiter:virtual public A
class Singer:virtual public A//虚基类
问题(2). A::show()被调用两次的问题
比如:
Singer::show(){A::show();...}
Waiter::show(){A::show();...}
SingerWaiter::show(){Singer::show();Waiter();...}//当调用SingerWaiter::show()时出现问题
解决:定义成保护类 protected 看上面定义
//A::
void A::Data()const{
cout << "my name is " << name << ". Id is " << id << endl;
}
void A::show()const{
cout << "Categor:A\n";
Data();
}
//Singer:
void Singer::Data()const{
cout << "His tyoe is " << stype << endl;
}
void Singer::show()const{
cout << "Categor:Singer\n";
Data();
}
//Waiter:
void Waiter::Data()const{
cout << "His year is " << year << endl;
}
void Waiter::show()const{
cout << "Categor:Waiter\n";
Data();
}
//SingerWaiter:
void SingerWaiter::Data()const{
Singer::Data();
Waiter::Data();
}
void SingerWaiter::show()const{
cout << "Categor:SingerWaiter: ";
if(sw)
cout << "yes!";
else
cout << "no!";
cout << endl;
A::Data();
Data();
}
二.类模板
1.定义
template <class Type>//与函数模板类似
class Stack
{
private:
enum {MAX = 10};
Type base[MAX];
int top;
public:
Stack();
bool isempty()const;
bool isfull()const;
bool push(const Type & a);
bool pop(Type & a);
};
//method:注意定义时与一般类的不同
template<class Type>//
Stack<Type>::Stack(){//
top = 0;
}
template<class Type>
bool Stack<Type>::isempty()const{
return top == 0;
}
2.使用
{
Stack<double> st1;
Stack<std::string> st2;
st1.push(1.25);
std::string str1 = "Liu";
st2.push(str1);//不能直接 st2.push("Liu");
}
三.多个参数类模板
1.多个参数
template <class T1,class T2>
class Pair
{
private:
T1 a;
T2 b;
public:
...
};
2.默认类型模板参数
template <class T1,class T2 = int>//与函数默认参数一样,必须从左边开始
class Pair
{
private:
T1 a;
T2 b;
public:
...
};
3.显示实例化
template class Array<string,100>
4.显示具体化
template <> class Array<char *>
{
...
}
未完待续…