赞
踩
面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。
当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。
一个类可以派生多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名,形式如下:
class derived -class:access-specifier base-class
//access-specifier是:public,protected或private;
//base-class是之前定义过的某个类的名称;
//未使用访问修饰符access-specifier,则默认为private。
实例:设计一个简单的TableTennisPlayer类,如:
头文件:
#ifndef TABTENN0_H #define TABTENN0_H #include<string> class TableTennisPlayer { private: string firstname; string lastname; bool hasTable; public: TableTennisPlayer(const string &fn="none", const string &ln="none",bool ht=false); void Name()const; bool HasTable() const { return hasTable;}; void ResetTable(bool v) { hasTable=v;}; }; #endif // TABTENN0_H
源文件:
#include<iostream>
#include"tabtenn0.h"
using namespace std;
TableTennisPlayer::TableTennisPlayer(const string &fn,
const string &ln, bool ht):
firstname(fn),lastname(ln),hasTable(ht){
}//使用初始化列表
void TableTennisPlayer::Name()const
{
cout<<lastname<<","<<firstname;
}
源文件2:
#include<iostream> #include"tabtenn0.h" int main() { //将c-风格字符串作为参数 TableTennisPlayer player1("Chuck","Blizzard",true); TableTennisPlayer player2("Tara","Boomdea",false); player1.Name(); if(player1.HasTable()) cout<<":has a table.\n"; else cout<<":hasn't a table.\n"; player2.Name(); if(player2.HasTable()) cout<<":has a table.\n"; else cout<<":hasn't a table.\n"; return 0; }
注:
const string &
,导致类型不匹配。const char *
作为参数的构造函数,使用c-风格字符串初始化对象时,将自动调用这个构造函数。const string &
作为参数的string构造函数)或c-风格字符串(调用const char *
作为参数的string构造函数)作为构造函数TableTennisPlayer
的参数。将RatedPlayer声明为TableTennisPlayer派生的基类:
class RatedPlayer:public TableTennisPlayer
{
}
注:
RatedPlayer对象将具有的特征:
Name(),hasTable()和RestTable()
方法:3.继承特性中需要添加什么?
派生类需要自己的构造函数。
派生类可以根据需要添加额外的数据成员和成员函数。
在例子中,派生类需要另一个数据来存储比分,还应包含检索比分的方法和重置比分的方法。因此,类声明与下面相似:
class RatedPlayer::public TableTennisPlayer
{
private:
unsigned int rating;
public:
RatedPlayer (unsigned int r=0,const string &fn="none",
const string &ln="none",bool ht=false);//每个成员对一个形参
RatedPlayer(unsigned int r,const TableTnnisPlayer & tp);//使用基类的形参
unsigned int Rating()const{
return rating;}
void ResetRating (unsigned int r){
rating = r;}
构造函数必须给新成员(如果有)和继承的成员提供数据。
派生类不能直接访问基类的私有成员,而必须通过基类方法访问。
RatedPlayer
构造函数不能直接设置继承的成员(firstname.lastname和hasTable
),而必须使用基类的公有方法来访问私有的基类成员。
派生类构造函数必须使用基类构造函数。
创建派生类对象时,程序首先创建基类对象。意味着基类对象应当在程序进入派生类构造函数之前被创建
c++使用成员初始化列表来完成工作,派生类会默认调用基类的无参构造。
派生类必须显示使用初始化列表调用基类的有参构造例如:下面是RatedPlayer构造函数代码:
RatedPlayer::RatedPlayer(unsigned int r,const string & fn,const string & ln,bool ht):TableTennisPlayer(fn,ln,ht)
{
rating=r;
}
//:TableTennisPlayer(fn,ln,ht)初始化列表,调用TableTennisPlayer构造函数。
例如:假设程序声明如下
:TableTennisPlayer(fn,ln,ht)
//则ReadPlayer构造函数将把实参`"Mallor","Duck"和“true”`赋给形参`fn,ln,ht`;
//然后将这些参数作为实参传递给TableTennisPlayer构造函数,后者将创建一个嵌套TableTennisPlayer对象,并将数据存储在该对象中。
//然后,程序进入ReadPlayer构造函数体,完成RealPlayer对象的创建,并将参数r的值赋给rating成员。
如果省略成员初始化列表,情况如何?
RatedPlayer::RatedPlayer(unsigned int r,const string & fn,const string & ln,bool ht)
{
rating=r;
}
必须首先创建基类对象,如果不调用基类构造函数,程序将使用默认的基类构造函数,因此上面的代码和下面等效:
RatedPlayer::RatedPlayer(unsigned int r,const string & fn,const string & ln,bool ht):TableTennisPlayer()
{
rating=r;
}
除非要使用默认构造函数,否则应显示调用基类的构造函数。例:
RatedPlayer::RatedPlayer(unsigned int r,const TableTnnisPlayer & tp):TableTnnisPlayer(tp)
{
rating=r;
}
由于tp的类型为TableTennisPlayer&
,因此将调用基类的复制构造函数。基类没有定义复制构造函数。但前面讲过需要复制构造函数而没定义,编译器会自动提供一个。
也可以对派生类成员使用初始化列表,这时,应该在列表中使用成员名,而不是类名。方法如下:
RatedPlayer(unsigned int r,const TableTnnisPlayer & tp):TableTennisPlayer(tp),rating(r)
{
}
注:有关派生类构造函数的要点:
例:
#include <iostream> using namespace std; class Base { public: Base() { cout<<"基类到的无参构造"<<endl; } ~Base() { cout<<"基类的析构函数"<<endl; } }; class Son:public Base { public: Son() { cout<<"派生类的无参构造"<<endl; } ~Son() { cout<<"派生类的析构函数"<<endl; } }; int main() { Son ob; }
注:
例:
#include <iostream> using namespace std; class Other { public: Other() { cout<<"对象成员的构造函数"<<endl; } ~Other() { cout<<"对象成员的析构函数"<<endl; } }; class Base { public: Base() { cout<<"基类到的无参构造"<<endl; } ~Base() { cout<<"基类的析构函数"<<endl; } }; class Son:public Base { public: Son() { cout<<"派生类的无参构造"<<endl; } ~Son() { cout<<"派生类的析构函数"<<endl; } Other ob;//对象成员 }; int main() { Son ob; }
注:
创建派生类对象时,程序首先调用基类构造函数,然后再调用派生类构造函数。
基类构造函数负责初始化基类的数据成员。
派生类构造函数主要用于初始化新增的数据成员。
派生类的构造函数总是调用一个基类构造函数,可以使用初始化列表语法指明要使用的基类构造函数,否则将使用默认的基类构造函数;
派生类对象过期时,程序首先调用派生类析构函数,然后再调用基类析构函数。
要使用派生类,程序必须要能够访问基类声明。下面的程序将这两种类的声明放在同个文件中。
//头文件: #ifndef TENN_H #define TENN_H #include<iostream> #include<string> using namespace std; class TableTennisPlayer { private: string firstname; string lastname; bool hasTable; public: TableTennisPlayer(const string &fn="none",const string &ln="none",bool ht=false); void Name()const; bool HasTable()const{ return hasTable;} void RestTable(bool v){ hasTable = v;} }; class RatedPlayer:public TableTennisPlayer { private: unsigned int rating; public: RatedPlayer(unsigned int r=0,const string &fn="none",const string &ln="none",bool ht=false); RatedPlayer(unsigned int r,const TableTennisPlayer &tp); unsigned int Rating()const{ return rating;} void ResetRating(unsigned int r){ rating=r;} }; #endif // TENN_H
//两个类定义
#include"tenn.h"
#include<iostream>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。