类设计中几种继承方式



通过继承能够从已有的类派生出新的类,而派生类继承了基类的特征,包括方法。正如继承一笔财产要比自己白手起家容易一样,通过继承派生出的类通常比设计新类要容易得多。下面是可以通过继承完成的一些工作。

①可以在已有类的基础上添加功能。

②可以给类添加数据。

③可以修改类方法的行为。

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。

使用保护继承时,基类的公有成员和保护成员都将成为派生类的保护成员。当从派生类派生(公有)出另一个类时,私有继承和保护继承之间的主要区别便呈现出来了。使用私有继承时,第三代将不能使用基类的接口,这是因为基类的公有方法在派生类中将变成私有方法。使用保护继承时,基类的公有方法在第三代中将变成受保护的,因此第三代派生类可以使用它们。

类设计中几种继承方式

时间: 2024-08-05 18:22:17

类设计中几种继承方式的相关文章

C++中三种继承方式的区别

本文来自https://zhidao.baidu.com/question/159111767.html  详细说明了三种继承方式的区别,好文 还可参考另一篇文章: https://blog.csdn.net/one_super_dreamer/article/details/81611118 https://blog.csdn.net/u011857683/article/details/82120998 public公有继承 protected保护继承 private私有继承 我们知道类的p

C++中的类继承(1) 三种继承方式

继承是使代码可以复用的重要手段,也是面向对象程序设计的核心思想之一.简单的说,继承是指一个对象直接使用另一对象的属性和方法.继承呈现了 面向对象程序设 计的层次结构, 体现了 由简单到复杂的认知过程.C++中的继承关系就好比现实生活中的父子关系,继承一笔财产比白手起家要容易得多,原始类称为基类,继承类称为子类,它们是类似于父亲和儿子的关系,所以也分别叫父类和子类.继承的方式有三种分别为公有继承(public),保护继承(protect),私有继承(private).定义格式如下: 1. 公有继承

C++中的三种继承方式

1,被忽略的细节: 1,冒号( :)表示继承关系,Parent 表示被继承的类,public 的意义是什么? 1 class Parent 2 { 3 4 }; 5 6 class Child : public Parent 7 { 8 9 }; 2,有趣的问题: 1,是否可以将继承语句中的 public 换成 protected 或者 private?如果可以,与 public 继承有什么区别? 3,有趣的尝试编程实验: 1 #include <iostream> 2 #include &l

js的三种继承方式及其优缺点

第一种,prototype的方式: //父类 function person(){ this.hair = 'black'; this.eye = 'black'; this.skin = 'yellow'; this.view = function(){ return this.hair + ',' + this.eye + ',' + this.skin; } } //子类 function man(){ this.feature = ['beard','strong']; } man.pr

js的5种继承方式——前端面试

js主要有以下几种继承方式:对象冒充,call()方法,apply()方法,原型链继承以及混合方式.下面就每种方法就代码讲解具体的继承是怎么实现的. 1.继承第一种方式:对象冒充 1 function Parent(username){ 2 this.username = username; 3 this.hello = function(){ 4 alert(this.username); 5 } 6 } 7 function Child(username,password){ 8 //通过以

Unity3d Android SDK接入解析(二)Unity3d Android SDK的设计与两种接入方式

一.前言 上篇说清楚了Unity和Android调用的方式,但很多实际接入的部分没有讲的很详细,因为重头在这篇,会详细讲述具体接入Android SDK的方式,和怎么去做一个方便Unity接入的SDK. 传送门: 前篇:Unity3d 与 Android之间的互相调用 http://blog.csdn.net/yang8456211/article/details/51331358 后篇:Unity3d Android SDK接入解析(三)接入Android Library的理解 http://

C++的三种访问权限与三种继承方式

三种访问权限 我们知道C++中的类,有三种访问权限(也称作访问控制),它们分别是public.protected.private.要理解它们其实也很容易,看下面了一个例子. 父类: class Person { public: Person(const string& name, int age) : m_name(name), m_age(age) { } void ShowInfo() { cout << "姓名:" << m_name <&l

三种继承方式和三种访问权限

 也就是说子类只能访问父类的保护和公有成员,而对象只能访问公有成员. 继承方式 1. 三种继承方式不影响子类对父类的访问权限,子类对父类只看父类的访问控制权.     2. 继承方式是为了控制子类(也称派生类)的调用方(也叫用户)对父类(也称基类)的访问权限. 3. public.protected.private三种继承方式,相当于把父类的public访问权限在子类中变成了对应的权限. 如protected继承,把父类中的public成员在本类中变成了protected的访问控制权限:priv

C++三种继承方式

一.三种继承方式 继承方式不同,第一个不同是的是派生类继承基类后,各成员属性发生变化.第二个不同是派生类的对象能访问基类中哪些成员发生变化.表格中红色标注. 1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 private: 7 int i; 8 protected: 9 int j; 10 public: 11 int k; 12 }; 13 14 class B:public A 15 { 16 17 }; 18