国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > C++ > 正文

C++教程:C++繼承的實(shí)現(xiàn)和方式

2020-05-23 14:25:35
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
了解繼承的概念之后,我們就來(lái)學(xué)習(xí)一下如何實(shí)現(xiàn)繼承。

私有和保護(hù)

在第14章中我們說(shuō)到,成員函數(shù)或成員數(shù)據(jù)可以是公有或者私有的。如果是公有的,那么它們可以被直接訪問(wèn);如果是私有的,那么它們無(wú)法被直接訪問(wèn)。同時(shí),我們還提到一個(gè)protected保留字,在沒(méi)有使用繼承的時(shí)候,它與private的效果是一樣的,即無(wú)法被直接訪問(wèn)。如果使用了繼承,我們就能體會(huì)到protected和private的差別。

private(私有)和protected(保護(hù))都能實(shí)現(xiàn)類的封裝性。private能夠?qū)ν獠亢妥宇惐C?,即除了成員所在的類本身可以訪問(wèn)之外,別的都不能直接訪問(wèn)。protected能夠?qū)ν獠勘C?,但允許子類直接訪問(wèn)這些成員。public、private和protected對(duì)成員數(shù)據(jù)或成員函數(shù)的保護(hù)程度可以用下表來(lái)描述:
C++教程:C++繼承的實(shí)現(xiàn)和方式

所以,當(dāng)我們使用到繼承的時(shí)候,必須考慮清楚:成員數(shù)據(jù)或成員函數(shù)到底應(yīng)該是私有的還是保護(hù)的。

一個(gè)簡(jiǎn)單的例子

首先我們以一個(gè)學(xué)生類為例,介紹繼承的寫法:(程序17.3.1)
//student.h
#include <iostream>
using namespace std;
class student//學(xué)生類作為父類
{
   public:
   student(char *n,int a,int h,int w);//帶參數(shù)的構(gòu)造函數(shù)
   student();//不帶參數(shù)的構(gòu)造函數(shù)
   void set(char *n,int a,int h,int w);//設(shè)置
   char * sname();
   int sage();
   int sheight();
   int sweight();
   protected:
   char name[10];//姓名
   int age;//年齡
   int height;//身高
   int weight;//體重
   private:
   int test;
};
char * student::sname()
{
   return name;
}
int student::sage()
{
   return age; 
}
int student::sheight()
{
   return height;
}
int student::sweight()
{
   return weight;
}
void student::set(char *n,int a,int h,int w)
{
   int i;
   for (i=0;n[i]!='/0';i++)
   {
      name[i]=n[i];
   }
   name[i]='/0';
   age=a;
   height=h;
   weight=w;
   return;
}
student::student(char *n,int a,int h,int w)
{
   cout <<"Constructing a student with parameter..." <<endl;
   set(n,a,h,w);
}
student::student()
{
   cout <<"Constructing a student without parameter..." <<endl;
}
//undergraduate.h
#include "student.h"
class Undergraduate:public student//本科生類作為子類,繼承了學(xué)生類
{
   public:
   double score();
   void setGPA(double g);//設(shè)置績(jī)點(diǎn)
   bool isAdult();//判斷是否成年
   protected:
   double GPA;//本科生績(jī)點(diǎn)
};
double Undergraduate::score()
{
   return GPA;
}
void Undergraduate::setGPA(double g)
{
   GPA=g;
   return;
}
bool Undergraduate::isAdult()
{
   return age>=18?true:false;//子類訪問(wèn)父類的保護(hù)成員數(shù)據(jù)
}
//main.cpp
#include <iostream>
#include "undergraduate.h"
using namespace std;
int main()
{
   Undergraduate s1;//新建一個(gè)本科生對(duì)象
   s1.set("Tom",21,178,60);
   s1.setGPA(3.75);
   cout <<s1.sname() <<endl;
   cout <<s1.sage() <<endl;
   cout <<s1.sheight() <<endl;
   cout <<s1.sweight() <<endl;
   cout <<s1.score() <<endl;
   cout <<s1.isAdult() <<endl;
   return 0;
}

運(yùn)行結(jié)果:
Constructing a student without parameter...
Tom
21
178
60
3.75
1
在使用繼承之前,我們必須保證父類是已經(jīng)定義好的。如果父類是虛無(wú)的、沒(méi)有被定義的,那么子類也就沒(méi)什么好繼承的了。定義一個(gè)子類的語(yǔ)法格式為:
    class 子類名:繼承方式父類名;
根據(jù)程序17.3.1的運(yùn)行結(jié)果,我們可以清楚地看到,學(xué)生類里面的公有和保護(hù)成員都已經(jīng)被繼承到本科生類。本科生類可以使用學(xué)生類的成員函數(shù),也可以訪問(wèn)學(xué)生類的保護(hù)成員。而本科生類中定義的成員則是對(duì)學(xué)生類的補(bǔ)充,并且也能夠被使用。

繼承的方式

在程序17.3.1中,我們選擇的繼承方式是public。和成員的類型一樣,除了public之外,繼承方式還有protected和private。那么,這三種繼承方式到底有什么區(qū)別呢?

public是公有繼承,或稱為類型繼承。它主要體現(xiàn)的是概念的延伸和擴(kuò)展,父類所有的公有、保護(hù)成員都將按部就班地繼承到子類中。父類的公有成員在子類中依然是公有的,父類的保護(hù)成員在子類中依然是保護(hù)的。比如程序17.3.1中的學(xué)生類和本科生類就是這樣的關(guān)系。

private是私有繼承,或稱為私有的實(shí)現(xiàn)繼承。它主要體現(xiàn)的是父類成員的重用。父類所有的公有、保護(hù)成員繼承到子類時(shí),類型會(huì)發(fā)生改變。父類的公有成員在子類中變成了私有成員,父類的保護(hù)成員在子類中也變成了私有成員。這時(shí),我們可以利用從父類繼承而來(lái)的成員函數(shù)來(lái)實(shí)現(xiàn)子類的成員函數(shù),并且不必?fù)?dān)心外部直接訪問(wèn)父類的成員函數(shù),破壞了子類的秩序。比如我們認(rèn)為棧是一種特殊的鏈表,它只能從鏈表尾部添加或刪除結(jié)點(diǎn),棧的壓棧和退棧功能可以方便地由鏈表類的成員函數(shù)實(shí)現(xiàn)。但是,如果外部還能直接訪問(wèn)從鏈表類繼承而來(lái)的成員函數(shù),那么就可以在棧的任何位置插入結(jié)點(diǎn),棧就會(huì)被破壞。

protected是保護(hù)繼承,或稱為保護(hù)的實(shí)現(xiàn)繼承。與私有繼承類似,它也是體現(xiàn)父類成員的重用。只不過(guò)父類的公有成員和保護(hù)成員在子類中都變成了保護(hù)成員。因此,如果有一個(gè)孫類繼承了子類,那么父類中的成員也將被繼承,成為孫類的保護(hù)成員。

public、private和protected三種繼承方式可以用下表描述。其中右下角的九個(gè)單元格表示各種父類成員在對(duì)應(yīng)的繼承方式下,成為子類成員后的性質(zhì)。
C++教程:C++繼承的實(shí)現(xiàn)和方式
在使用繼承的時(shí)候,我們必須根據(jù)實(shí)際需要選擇合適的繼承方式。下面我們以棧繼承鏈表為例,理解一下私有繼承方式:(程序17.3.2)
//node.h
#include <iostream>
using namespace std;
class Node
{
friend class Linklist;//鏈表類作為友元類
friend class Stack;//棧類作為友元類
public:
Node();
Node(Node &n);
Node(int i,char c='0');
Node(int i,char c,Node *p,Node *n);
~Node();
private:
int idata;
char cdata;
Node *prior;
Node *next;
};
Node::Node()
{
cout <<"Node constructor is running..." <<endl;
idata=0;
cdata='0';
prior=NULL;
next=NULL;
}
Node::Node(int i,char c)
{
cout <<"Node constructor is running..." <<endl;
idata=i;
cdata=c;
prior=NULL;
next=NULL;
}
Node::Node(int i,char c,Node *p,Node *n)
{
cout <<"Node constructor is running..." <<endl;
idata=i;
cdata=c;
prior=p;
next=n;
}
Node::Node(Node &n)
{
idata=n.idata;
cdata=n.cdata;
prior=n.prior;
next=n.next;
}
Node::~Node()
{
cout <<"Node destructor is running..." <<endl;
}
//linklist.h
#include "node.h"
#include <iostream>
using namespace std; 
class Linklist
{
public:
Linklist(int i=0,char c='0');
Linklist(Linklist &l);
~Linklist();
bool Locate(int i);
bool Locate(char c);
bool Insert(int i=0,char c='0');
bool Delete();
void Show();
void Destroy();
protected://原私有成員改為保護(hù)成員,以便于Stack類繼承
Node head;
Node * pcurrent;
};
Linklist::Linklist(int i,char c):head(i,c)
{
cout<<"Linklist constructor is running..."<<endl;
pcurrent=&head;
}
Linklist::Linklist(Linklist &l):head(l.head)
{
cout<<"Linklist Deep cloner running..." <<endl;
pcurrent=&head;
Node * ptemp1=l.head.next;
while(ptemp1!=NULL)
{
Node * ptemp2=new Node(ptemp1->idata,ptemp1->cdata,pcurrent,NULL);
pcurrent->next=ptemp2;
pcurrent=pcurrent->next;
ptemp1=ptemp1->next;
}
}
Linklist::~Linklist()
{
cout<<"Linklist destructor is running..."<<endl;
Destroy();
}
bool Linklist::Locate(int i)
{
Node * ptemp=&head;
while(ptemp!=NULL)
{
if(ptemp->idata==i)
{
pcurrent=ptemp;
return true;
}
ptemp=ptemp->next;
}
return false;
}
bool Linklist::Locate(char c)
{
Node * ptemp=&head;
while(ptemp!=NULL)
{
if(ptemp->cdata==c)
{
pcurrent=ptemp;
return true;
}
ptemp=ptemp->next;
}
return false;
}
bool Linklist::Insert(int i,char c)
{
if(pcurrent!=NULL)
{
Node * temp=new Node(i,c,pcurrent,pcurrent->next);
if (pcurrent->next!=NULL)
{
pcurrent->next->prior=temp;
}
pcurrent->next=temp;
return true;
}
else
{
return false;
}
}
bool Linklist::Delete()
{
if(pcurrent!=NULL && pcurrent!=&head)
{
Node * temp=pcurrent;
if (temp->next!=NULL)
{
temp->next->prior=pcurrent->prior;
}
temp->prior->next=pcurrent->next;
pcurrent=temp->prior;
delete temp;
return true;
}
else
{
return false;
}
}
void Linklist::Show()
{
Node * ptemp=&head;
while (ptemp!=NULL)
{
cout <<ptemp->idata <<'/t' <<ptemp->cdata <<endl;
ptemp=ptemp->next;
}
}
void Linklist::Destroy()
{
Node * ptemp1=head.next;
while (ptemp1!=NULL)
{
Node * ptemp2=ptemp1->next;
delete ptemp1;
ptemp1=ptemp2;
}
head.next=NULL;
}
//stack.h
#include "linklist.h"
class Stack:private Linklist//私有繼承鏈表類
{
public:
bool push(int i,char c);
bool pop(int &i,char &c);
void show();
};
bool Stack::push(int i,char c)
{
while (pcurrent->next!=NULL)
pcurrent=pcurrent->next;
return Insert(i,c);//用鏈表類的成員函數(shù)實(shí)現(xiàn)功能
}
bool Stack::pop(int &i,char &c)
{
while (pcurrent->next!=NULL)
pcurrent=pcurrent->next;
i=pcurrent->idata;
c=pcurrent->cdata;
return Delete();//用鏈表類的成員函數(shù)實(shí)現(xiàn)功能
}
void Stack::show()
{
Show();//用鏈表類的成員函數(shù)實(shí)現(xiàn)功能
}
//main.cpp
#include <iostream>
#include "stack.h"
int main()
{
Stack ss;
int i,j;
char c;
for (j=0;j<3;j++)
{
cout <<"請(qǐng)輸入一個(gè)數(shù)字和一個(gè)字母:" <<endl;
cin >>i >>c;
if (ss.push(i,c))
{
cout <<"壓棧成功!" <<endl;
}
}
ss.show();
while (ss.pop(i,c))
{
cout <<"退棧數(shù)據(jù)為i=" <<i <<" c=" <<c <<endl;
}
return 0;
}
運(yùn)行結(jié)果:
Node constructor is running...
Linklist constructor is running...
請(qǐng)輸入一個(gè)數(shù)字和一個(gè)字母:
1 a
Node constructor is running...
壓棧成功!
請(qǐng)輸入一個(gè)數(shù)字和一個(gè)字母:
2 b
Node constructor is running...
壓棧成功!
請(qǐng)輸入一個(gè)數(shù)字和一個(gè)字母:
3 c
Node constructor is running...
壓棧成功!
0 0
1 a
2 b
3 c
Node destructor is running...
退棧數(shù)據(jù)為i=3 c=c
Node destructor is running...
退棧數(shù)據(jù)為i=2 c=b
Node destructor is running...
退棧數(shù)據(jù)為i=1 c=a
Linklist destructor is running...
Node destructor is running...

我們看到,Stack類私有繼承了Linklist類之后,利用Linklist的成員函數(shù),方便地實(shí)現(xiàn)了壓棧和退棧功能。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 永德县| 锦州市| 武陟县| 松原市| 汝阳县| 奈曼旗| 梧州市| 南郑县| 鸡东县| 钟山县| 剑川县| 邯郸县| 会昌县| 德庆县| 漯河市| 西充县| 永平县| 青岛市| 睢宁县| 岗巴县| 梅州市| 长白| 绥宁县| 西乌珠穆沁旗| 红原县| 原平市| 郓城县| 崇左市| 塘沽区| 东乌珠穆沁旗| 韩城市| 泾源县| 平武县| 平谷区| 体育| 安顺市| 虞城县| 遵义县| 丰宁| 罗田县| 勃利县|