码迷,mamicode.com
首页 > 其他好文 > 详细

类设计中几种继承方式

时间:2014-07-28 16:32:53      阅读:506      评论:0      收藏:0      [点我收藏+]

标签:设计   继承      多态   友元   



通过继承能够从已有的类派生出新的类,而派生类继承了基类的特征,包括方法。正如继承一笔财产要比自己白手起家容易一样,通过继承派生出的类通常比设计新类要容易得多。下面是可以通过继承完成的一些工作。
①可以在已有类的基础上添加功能。
②可以给类添加数据。
③可以修改类方法的行为。
C++有三种继承方式:公有继承、保护继承和私有继承。
一、公有继承
公有继承是最常用的方式,它建立一种is-a关系,即派生类对象也是一个基类对象,可以对基类对象执行的任何操作,也可以对派生类对象执行。
①公有继承不建立has-a关系。例如,午餐可能包含水果,但是通常午餐并不是水果,因此不能从水果类派生出午餐类。
②公有继承不能建立is-like-a关系,也就是说,它不采用明喻。人们通常说律师就是鲨鱼,但是律师并不是鲨鱼,因此不能从鲨鱼派生出律师。
③公有继承不建立is-implemented-as-a(作为......来实现)关系。例如,可以用数组来实现堆栈,但是从数组类派生出堆栈类时不合适的,因为堆栈不是数组,至少数组索引不是堆栈的属性。正确做法是:通过让堆栈包含一个私有数组对象成员,来隐藏数组实现。
④公有继承不建立uses-a关系。例如,计算机可以使用激光打印机,但是从Computer类派生出Printer类是没有意义的。不过可以使用友元函数或类来处理Printer对象和Computer对象之间的关系。
多态公有继承
实现机制:
①在派生类中重新定义基类的方法。
②使用虚方法。
例如:
class A
{
public:
 virtual ~A(){}
 virtual void show()
 {
  cout << "A" << endl;
 }
};

class B:public A
{
public:
 void show()
 {
  cout << "B" << endl;
 }
};

class C:public B
{
public:
 void show()
 {
  cout << "C" << endl;
 }
};

int main()
{
  C c;
 A a;
  A *pA = new C;
 B b;
 B *pB = new C;
 a.show();
 b.show();
 c.show();
 pA->show();
 pB->show();
 delete pA;
 delete pB;
}

1)可以看出基类中的方法show()在派生类中的行为是不同的,程序将使用对象类型来确定使用哪个版本。例如:
a.show();//use A::show()
b.show();//use B::show()
c.show();//use C::show()
2)使用virtual之后,如果方法是通过引用或者指针而不是对象引用的,它将确定使用那一种方法。如果没有使用关键字virtual,程序将根据引用类型或指针类型选择方法;如果使用了virtual,程序将根据引用或指针指向的对象的类型来选择方法。例如:
如果基类中的show()没有使用virtual,那么
pA->show();//use A::show()
pB->show();//use B::show()
如果基类中的show()使用了virtual,那么
pA->show();//use C::show()
pB->show();//use C::show()
大家可能会疑惑,类B作为类C的基类,其中的方法show()没有被声明为virtual,但是为什么同样调用的是对象c中的方法。这里我们必须清楚一点,方法在基类中被声明为虚拟后,它在派生类中将自动成为虚方法。
3)基类声明类一个虚拟析构函数,这样做是为了确保释放派生对象时,按照正确的顺序调用析构函数。当使用delete释放由new分配的对象时,如果析构函数不是虚拟的,则将只调用对应于指针类型的析构函数,例如上面的只调用类型A和类型B的析构函数,即使指针指向的是一个C对象。如果析构函数是虚拟的,将调用相应对象类型的析构函数。因此如果指针指向的C对象,将调用C的析构函数,然后子宫调用基类的析构函数。因此,使用虚拟析构函数可以确保正确的析构函数序列被调用。
4)private和protected之间的区别只有在基类派生类中才会表现出来。派生类的成员可以直接访问基类的保护成员,但不能直接访问基类的私有成员。因此对于外部世界来说,保护成员的行为与私有成员类似;但对于派生类来说,保护成员的行为与公有成员相似。
5)构造函数不能是虚函数。创建派生类对象时,将调用派生类的构造函数,而不是基类的构造函数,然后,派生类的构造函数将使用基类的一个构造函数,这种顺序不同于继承机制。因此,派生类不继承基类的构造函数,所以将类构造函数声明为虚拟的没有什么意义。
二、私有继承
C++的一个主要目标是促进代码重用。公有继承是实现这种目标的机制之一,但并不是惟一的机制。如果一个类本身是另一个类的对象。这种方法称为包含、组合或层次化。还可以通过使用私有或保护继承,实现这种包含关系。通常,包含、私有继承和保护继承用于实现has-a关系,即新的类将包含另一个类的对象。
使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员。这意味着基类方法将不会称为派生类对象公有接口的一部分,但可以在派生类的成员函数中使用它们。
使用公有继承,基类的公有方法将成为派生类的公有方法。简而言之,派生类将继承基类的接口;这是is-a关系的一部分。
使用私有继承,基类的公有方法将成为派生类的私有方法。简而言之,派生类不继承基类的接口。这种不完全继承是has-a关系的一部分。
包含将对象作为一个命名的成员对象添加到类中,而私有继承将对象作为一个未被命名的继承对象添加到类中。
包含:
#include <string>
#include <valarray>
using namespace std;
class student
{
public:
 double Average() const;
private:
 typedef valarray<double> ArrayDb;
 string name;//contained object
 ArrayDb scores;//contained object
};

私有继承:
class student:private string,private valarray<double>
{
public:
 double Average() const;
 const string& Name() const;
...
};

1)初始化基类组件
对于构造函数,包含将使用这样的构造函数:
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),valarray<double>(pd,n){}
2)访问基类的方法
包含使用对象来调用方法:
double student::Average() const
{
 if (scores.size() > 0)
  return scores.sum()/scores.size();
 else
  return 0;
}
而私有继承使得能够使用类名和作用域解析操作符来调用基类的方法
double student::Average() const
{
 if (valarray<double>::size() > 0)
  return valarray<double>::sum()/valarray<double>::size();
 else
  return 0;
}
3)访问基类对象
使用私有继承时,该string对象没有名称,那么,student类的代码如何访问内部的string对象呢?答案是使用强制类型转换。由于student类是从string类派生而来的,因此可以通过强制类型转换,将student对象转换为string对象;结果为继承而来的string对象。
const string& student::Name() const
{
 return (const string&) *this;
}
上述方法返回一个引用,该应用指向用于调用该方法的student对象中的继承而来的string对象。
4)访问基类的友元函数
用类名显示地限定函数名不适合于友元函数,这是因为友元不属于类。不过可以通过显示地转换为基类来调用正确的函数。例如,对于下面的友元函数定义:
ostream& operator << (ostream& os,const student& stu)
{
 os << "scores for " << (const string&)stu << ":\n";
 ...
}
注意:引用stu不会自动转换为string引用,根本原因在于,在私有继承中,在不进行显式类型转换的情况下,不能将指向派生类的引用或指针赋给基类引用或指针。
三、保护继承
保护继承是私有继承的变体。保护继承在列出基类时使用关键字protected。
使用保护继承时,基类的公有成员和保护成员都将成为派生类的保护成员。当从派生类派生(公有)出另一个类时,私有继承和保护继承之间的主要区别便呈现出来了。使用私有继承时,第三代将不能使用基类的接口,这是因为基类的公有方法在派生类中将变成私有方法。使用保护继承时,基类的公有方法在第三代中将变成受保护的,因此第三代派生类可以使用它们。

类设计中几种继承方式,布布扣,bubuko.com

类设计中几种继承方式

标签:设计   继承      多态   友元   

原文地址:http://blog.csdn.net/fayery/article/details/38189431

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!