C++中的类继承
作者:互联网
C++类提供了更高层次的重用性。目前,很多厂商提供了类库,类库由类声明和实现构成。因为类组合了数据表示和类方法,因此提供了比函数库更加完整的程序包。
1、一个简单的基类
从一个类派生出另一个类时,原始类成为基类,继承类称为派生类。
tabtenn0.h
#ifndef TABTENN0_H_
#define TABTENN0_H_
#include <string>
class TableTennisPlayer
{
private:
std::string fristname;
std::string lastname;
bool hasTable;
public:
TableTennisPlayer(const std::string& fn = "none",
const std::string& ln = "none", bool ht = false);
void Name() const;
bool HasTable() const { return hasTable; }
void ResetTable(bool v) { hasTable = v; }
};
#endif
tabtenn0.cpp
#include "tabtenn0.h"
#include <iostream>
//构造函数
TableTennisPlayer::TableTennisPlayer(const std::string& fn,
const std::string& ln, bool ht) :firstname(fn),
lastname(ln), hasTable(ht)
{}
void TableTennisPlayer::Name() const
{
std::cout << lastname << ", " << firstname << std::endl;
}
派生一个类,包含成员在比赛中的比分。
class RatePlayer:public TableTennisPlayer
{
private:
unsigned int rating; //比分
public:
//派生类的构造函数
RatePlayer(unsigned int r = 0, const std::string& fn = "none",
const std::string& ln = "none", bool ht = false);
RatePlayer(unsigned int r, const TableTennisPlayer& tp);
//添加派生类的方法
unsigned int Rating() const { return rating; }
void ResetRating(unsigned int r) { rating = r; }
};
构造函数必须给新成员和继承的成员提供数据。
派生类不能直接访问基类的私有成员,而必须通过基类方法进行访问。派生类构造函数必须使用基类构造函数。
创建派生类对象时,程序首先创建基类对象。从概念上说,这意味着基类对象应当在程序进入派生类构造函数之前被创建。C++使用成员初始化列表语法来完成这种工作。
RatedPlayer::RatedPlayer(unsigned int r, const string& fn,
const string& ln, bool ht): TableTennisPlayer(fn, ln, ht)
{
rating=r;
}
其中:TableTennisPlayer(fn,ln,ht)是成员初始化列表。他是可执行的代码,调用TableTennisPlayer构造函数。
有关派生类构造函数的要点如下:
- 首先创建基类对象;
- 派生类构造函数应通过成员初始化列表将基类信息传递给基类构造函数;
- 派生类构造函数应初始化派生类新增的数据成员。
创建派生类对象时,程序首先调用基类的构造函数,然后再调用派生类构造函数。基类构造函数负责初始化继承类的数据成员;派生类构造函数主要用于初始化新增的数据成员。派生类的构造函数总是调用一个基类的构造函数。可以使用初始化器列表语法指明要使用的基类构造函数,否则将使用默认的基类构造函数。
派生类对象过期时,程序将首先调用派生类析构函数,然后再调用基类构造函数。
1.1、派生类和基类之间的特殊关系
派生类和基类之间有一些特殊关系,其中之一是派生类对象可以使用基类的方法,条件是方法不是私有的;同时基类指针可以在不进行显示类型转换的情况下指向派生类对象。然而基类指针或引用只能用于调用基类方法。
2、多态公有继承
派生类对象使用基类的方法,而未做任何修改。然而,应该会遇到这样的情况,即希望同一个方法在派生类和基类中的行为是不同的。换句话来说,方法的行为应该取决于调用该方法的对象。这种较复杂的行为称为多态——具有多种形态。有两种重要的机制可用于实现多态公有继承:
- 在派生类中重新定义基类的方法
- 使用虚方法
另一个例子。银行开发两个类,一个类用于表示基本支票账户——Brass Account,另一个类用于表示Brass Plus支票账户,它添加了透支保护特性。
#ifndef BRASS_H_
#define BRASS_H_
#include <string>
class Brass
{
private:
std::string fullName; //客户姓名
long acctNum; //账户
double balance; //当前余额
public:
Brass(const std::string& s = "Nullbody", long an = -1,
double bal = 0.0);
void Deposit(double amt);
double Balance() const;
virtual void ViewAcct() const;
virtual ~Brass();
};
class BrassPlus : public Brass
{
private:
double maxLoan; //透支上限
double rate; //透支贷款利率
double owesBank; //当前的透支总额
public:
//继承类的构造函数在声明时不需要对基类进行构造函数初始化
BrassPlus(const std::string& s = "Nullbody", long an = -1,
double bal = 0.0, double ml = 500,
double r = 0.11125);
BrassPlus(const Brass& ba, double ml = 500, double r = 0.11125);
virtual void ViewAcct() const;
virtual void Withdraw(double amt);
void ResetMax(double m) { maxLoan = m; }
void ResetRate(double r) { rate = r; }
void ResetOwes() { owesBank = 0; }
};
#endif
程序需要说明一下几点:
- BrassPlus类在Brass类的基础上添加了3个私有成员和3个公有函数;
- Brass类和BrassPlus类都声明了ViewAcct()和Withdraw()方法,但BrassPlus对象和Brass对象的这些方法的行为是不同的;
- Brass类在声明ViewAcct()和Withdraw()时使用了新关键词virtual。这些方法被称为虚方法;
- Brass类还声明了一个虚析构函数,虽然该析构函数不执行任何操作。
第二点介绍了声明如何指出方法在派生类的行为的不同。两个ViewAcct()原型表明将有2个独立的方法定义。基类版本的限定名为Brass::ViewAcct(),派生类版本的限定名为BrassPlus::ViewAcct()。程序将使用对象类型来确定使用哪个版本:
Brass dom("Dominic Banker", 11224, 4183.45);
BrassPlus dot("Dorothy Banker", 12118, 2592.00);
dom.ViewAcct(); //使用Brass::ViewAcct()方法
dot.ViewAcct(); //使用BrassPlus::ViewAcct()方法
第三点使用virtual要复杂一点。如果方法是通过引用或指针而不是对象调用的,它将确定使用哪一种方法。如果没有使用关键字virtual,程序将根据引用类型或者指针类型选择方法;如果使用了virtual,程序将根据引用或指针指向的对象的类型来选择方法。
方法在基类中被声明为虚的后,他在派生类中将自动成为虚方法。然而在派生类声明中使用关键字virtual来指出哪些函数是虚函数也不失为一个好办法。
如果要在派生类中重新定义基类的方法,通常应将基类方法声明为虚的。这样程序将根据对象类型而不是引用或指针的类型来选择方法版本。
2.1、为何需要虚析构函数
使用delete释放由new分配的对象的代码说明了为何基类应包括一个虚析构函数,虽然有时候好像并不需要析构函数。如果虚构函数不是虚的,则只调用对应于指针类型的析构函数。如果析构函数是虚的,将调用响应对象类型的析构函数。因此,如果指针指向的是BrassPlus对象,将调用BrassPlus的析构函数,然后自动调用基类的析构函数。
3、访问控制符:protected
关键字protected和private相似,在类外只能用于共有类成员来访问protected部分中的类成员。private和protected之间的区别只有在基类派生的类中才会表现出来。派生类的成员可以直接访问基类的保护成员,但不能直接访问基类的私有成员。因此,对于外部世界来说,保护成员的行为与私有成员相似;但对于派生类来说,保护成员与公有成员相似。
标签:const,继承,double,基类,C++,派生类,Brass,构造函数 来源: https://blog.csdn.net/qq_41455814/article/details/121151701