一、c++中的继承
1.可以在已有类的基础上添加功能
2.可以给类添加数据
3.可以修改类的方法行为
基类:从一个类派生出另一个类时,原始类称为基类,继承类称为派生类。
二、继承demon(参考自c++书籍)
#include<iostream>
#include<string>
using std::string;
using namespace std;
class Table
{
private:
string firstname;
string lastname;
bool hasTable;
public:
Table (const string & fn = "name",const string & ln = "none",
bool ht = false);
void Name() const;
bool HasTable() const { return hasTable;}
void RestTable(bool v) { hasTable = v;};
};
//成员列表初始化语法
Table::Table(const string & fn,const string & ln,bool ht):firstname(fn),lastname(ln),hasTable(ht)
{
}
void Table::Name() const
{
std::cout<<lastname<<","<<firstname;
}
class RatedPlayer : public Table
{
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 Table & tp);
unsigned int Rating() const { return rating; }
void RestRating(unsigned int r) { rating = r; }
};
/************************************************************************
**关于派生类构造函数要点
**1.首先创造基类对象;
**2.派生类构造函数应通过成员初始化列表将基类信息传给基类构造函数;
**3.派生类构造函数应初始化派生类新增的数据成员
**【注】:创建派生类构造函数时应先调用基类的构造函数再调用派生类构造函数
** 派生类对象消亡时,先调用派生类析构函数,再调用基类的析构函数
*************************************************************************/
RatedPlayer::RatedPlayer(unsigned int r,const string & fn,const string & ln,bool ht) : Table(fn,ln,ht)
{
rating = r;
}
RatedPlayer::RatedPlayer(unsigned int r,const Table & tp) : Table(tp),rating(r)
{
}
int main()
{
using std::cout;
Table player1("chuck","Blizzard",true);
Table player2("Tara","Boomdea",false);
RatedPlayer rplayer1(1140,"Mallory","Duck",true);
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<<":has`t a Table.\n";
cout << "Name :";
rplayer1.Name();
cout << "; Rating: "<< rplayer1.Rating() << endl;
RatedPlayer rplayer2(5233,player1);
cout << "Name:";
cout << "Rating: "<<rplayer2.Rating() << endl;
return 0;
}
运行结果:

三、派生类和基类之间的特殊关系
1.
派生类对象可以使用基类的方法,条件是方法不是私有的
2.
基类指针可以在不进行显式类型转换的情况下指向派生类对象
3.
基类引用可以在不进行显示类型转换的情况下引用派生类对象
以上示demon为例子
Table & rt = rplayer;
Table * pt = rplayer;
rt.Name(); //引用调用
pt->Name();//指针使用
【注】1.基类指针只能调用基类方法,不能调用派生类方法
2.不可以将基类的地址赋给派生类引用和指针
4.
基类引用定义的函数或指针参数可用于基类对象或派生类对象
void Show(const Table & rt)
{
using std::cout;
cout << "Name: ";
rt.Name();
cout << "\nTable: ";
if(rt.HasTable())
cout << "yes\n";
else
cout << "no\n";
}
//player1 ---基类对象
//rplayer1 --派生类对象
Show(player1); //argument
Show(rplayer1); //argument
5.
可以将基类对象初始化为派生类对象
6.
可以将派生类对象赋给基类对象
四、继承:is-a关系
c++3种继承方式:
公有继承、保护继承、私有继承
1.公有继承:
建立的是is-a的关系,即派生类对象也是一个基类对象
is-a-kind-of:
往派生类中添加特性,属于is-a-kind-of关系
has-a:
例如fruit类和lunch类,lunch类可以包含furit类,但是furit类不能派生lunch类在午餐中添加水果(午餐中可以有水果,但水果不能包含全部的午餐属性)
五、多态公有继承
实现多有公态的重要机制
1.在派生类中重新定义基类的方法
2.使用虚方法
1.virtual关键字
virtual
在英文中表示“虚”、“虚拟”的含义。c++中的关键字“virtual”用于表示虚函数与虚基类。
1-1虚函数
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);//存款
virtual void Withdraw(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 sdt::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 ViewAct() const;
virtual void Withdraw(double amt);//取款
void ResetMax(double m) { maxLoan = m };
void ResetRate(double r) { rate = r; }//利率
void ResetOwes() { owesBank = 0; }//负债
};
使用virtual与未使用virtual关键字对比
/**未使用virtual**/
Brass dom("Brass",11224,5000.00);
BrassPlus dop("BraasP",111222,6000.01);
Brass & b1 = dom;
Brass & b2 = dop;
b1.ViewAct();//使用基类Brass方法
b2.ViewAct();//使用基类Brass方法
/**使用virtual**/Brass dom("Brass",11224,5000.00);
BrassPlus dop("BraasP",111222,6000.01);
Brass & b1 = dom;
Brass & b2 = dop;
b1.ViewAct();//使用基类Brass方法
b2.ViewAct();//使用派生类BrassPlus方法
银行存取款demon(参考自c++教程)
#include<iostream>
#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);//存款
virtual void Withdraw(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 = 5000,double r = 0.11125);
BrassPlus(const Brass & ba, double ml = 5000,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; }//负债
};
using std::cout;
using std::endl;
using std::string;
typedef std::ios_base::fmtflags format;
typedef std::streamsize precis;
format setFormat();
void restore(format f, precis p);
Brass::Brass(const string & s,long an,double bal)
{
fullName = s;
acctNum = an;
balance = bal;
}
//存款
void Brass::Deposit(double amt)
{
if (amt < 0)
cout << "存款须为正"<<endl;
else
balance += amt;
}
//取款
void Brass::Withdraw(double amt)
{
format initialState = setFormat();
precis prec = cout.precision(2);
if (amt < 0)
cout <<"取款额须为正"<<endl;
else if(amt <= balance)
balance -= amt;
else
cout <<"账户余额:"<<balance<<" | 取款额:"<< amt <<"| 取款额度超过账户余额,取款失败" << endl;
restore(initialState,prec);
}
double Brass::Balance() const
{
return balance;
}
//查看客户信息
void Brass::ViewAcct() const
{
format initialSate = setFormat();
precis prec = cout.precision(2);
cout << "客户: " << fullName << endl;
cout << "账户 Acount Number: " << acctNum <<endl;
cout << "余额 Balance : " << balance <<endl;
restore(initialSate,prec);
}
Brass::~Brass()
{
}
//派生类的实现
BrassPlus::BrassPlus(const string & s,long an,double bal,double ml, double r) : Brass(s,an,bal)
{
maxLoan = ml;
owesBank = 0.0;
rate = r;
}
BrassPlus::BrassPlus(const Brass & ba,double ml, double r) : Brass(ba)
{
maxLoan = ml;
owesBank = 0.0;
rate = r;
}
//查看借款信息
void BrassPlus::ViewAcct() const
{
format initialSate = setFormat();
precis prec = cout.precision(2);
Brass::ViewAcct();
cout << "最大借款额度:"<< maxLoan << endl;
cout << "账户已借款:" << owesBank << endl;
cout << "利率:" << 100 * rate <<"%\n";
restore(initialSate, prec);
}
//取款
void BrassPlus::Withdraw(double amt)
{
format initialSate = setFormat();
precis prec = cout.precision(2);
double bal = Balance();
if(amt <= bal )
Brass::Withdraw(amt);
else if (amt <= bal + maxLoan - owesBank )
{
double advance = amt - bal;
owesBank += advance * (1.0+rate);
cout << "预支取 :" << advance << endl;
cout << "最后须偿还利息:" << advance *rate << endl;
Deposit(advance);
Brass::Withdraw(amt);
}
else
cout << "取款超出了限制" << endl;
restore(initialSate,prec);
}
//将浮点值得输出模式设置为定点
format setFormat()
{
return cout.setf(std::ios_base::fixed,std::ios_base::floatfield);
}
//重置格式和精度
void restore (format f,precis p)
{
cout.setf(f,std::ios_base::floatfield);
cout.precision(p);
}
int main()
{
Brass B_Object("张三",888999,4000.00);
BrassPlus P_Object("李四",666888,3000.00);
B_Object.ViewAcct();
P_Object.ViewAcct();
cout << endl;
cout << "存款1000到李四账户\n";
P_Object.Deposit(1000.00);
cout<<"nwe balance si "<<P_Object.Balance() << endl;
cout << "\n张三取款5000\n";
B_Object.Withdraw(5000.00);
B_Object.ViewAcct();
cout << "\n李四取款8000\n";
P_Object.Withdraw(8000.00);
P_Object.ViewAcct();
return 0;
}
运行结果:
六、关键字protected
关键字protected:
关键字protected和private相似,在类外只能用公有类成员来访问protected部分的类成员。 派生类可以直接访问基类的保护部分成员,但不能直接访问私有成员
七、使用动态内存分配和友元示例
#include<iostream>
#include<cstring>
//基类
class baseDMA
{
private:
char *label;
int rating;
public:
baseDMA(const char *l = "null",int r = 0);
baseDMA(const baseDMA & rs);
virtual ~baseDMA(); //析构
baseDMA & operator=(const baseDMA & rs);//重载运算符
friend std::ostream & operator<<(std::ostream & os,const baseDMA & rs);//友元重载<<
};
//派生类
class lacksDMA : public baseDMA
{
private:
enum { COL_LEN = 40 };
char color[COL_LEN];
public:
lacksDMA(const char * c ="blank",const char * l = "null",int r = 0);
lacksDMA(const char * c,const baseDMA & rs);
friend std::ostream & operator<<(std::ostream & os,const lacksDMA & rs);
};
//派生类
class hasDMA : public baseDMA
{
private :
char * style;
public :
hasDMA(const char * s = "none",const char * l = "null",int r = 0);
hasDMA(const char * s,const baseDMA & rs);
hasDMA(const hasDMA & hs);
~hasDMA();
hasDMA & operator=(const hasDMA & rs);
friend std::ostream & operator<<(std::ostream & os,const hasDMA & rs);
};
/**基类的实现**/
baseDMA::baseDMA(const char * l,int r)
{
label = new char[std::strlen(l)+1];
std::strcpy(label,l);
rating = r;
}
baseDMA::baseDMA(const baseDMA & rs)
{
label = new char[std::strlen(rs.label) + 1];
std::strcpy(label,rs.label);
rating = rs.rating;
}
baseDMA::~baseDMA()
{
delete [] label;
}
baseDMA & baseDMA::operator=(const baseDMA & rs)
{
if( this == &rs )
return *this;
delete [] label;
label = new char[std::strlen(rs.label) + 1];
std::strcpy(label,rs.label);
rating = rs.rating;
return *this;
}
std::ostream & operator<<(std::ostream & os,const baseDMA & rs)
{
os << "label: " << rs.label << std::endl;
os << "Rating: " << rs.rating << std::endl;
return os;
}
/**派生类**/
lacksDMA::lacksDMA(const char * c,const char * l,int r ) : baseDMA(l,r)
{
std::strncpy(color,c,39);
color[39] = '\0';
}
lacksDMA::lacksDMA(const char *c,const baseDMA & rs) : baseDMA(rs)
{
std::strncpy(color,c,COL_LEN - 1);
color[COL_LEN - 1] = '\0';
}
std::ostream & operator<<(std::ostream & os,const lacksDMA & ls)
{
os << (const baseDMA &)ls;
os << "Color: " << ls.color << std::endl;
return os;
}
/**派生类2**/
hasDMA::hasDMA(const char *s,const char *l,int r) : baseDMA(l,r)
{
style = new char[std::strlen(s) + 1];
std::strcpy(style,s);
}
hasDMA::hasDMA(const hasDMA &hs) : baseDMA(hs)
{
style = new char[std::strlen(hs.style) + 1];
std::strcpy(style,hs.style);
}
hasDMA::~hasDMA()
{
delete [] style;
}
hasDMA & hasDMA::operator=(const hasDMA & hs)
{
if ( this == &hs)
return *this;
baseDMA::operator=(hs);
delete [] style;
style = new char[std::strlen(hs.style) + 1];
std::strcpy(style,hs.style);
return *this;
}
std::ostream & operator<<(std::ostream & os,const hasDMA & hs)
{
os << (const baseDMA &)hs;
os << "Style: " << hs.style << std::endl;
return os;
}
int main()
{
using std::cout;
using std::endl;
baseDMA shirt("Portabelly",8);//对象衬衣
lacksDMA balloon("read","Blimpo",4);//对象气球
hasDMA map("Mercator","Buffalo keys",5);//地图对象
cout << "显示基类对象信息:\n";
cout << shirt << endl;
cout << "显示lacksDMA类对象信息:\n";
cout << balloon << endl;
cout << "显示hasDMA类对象信息:\n";
cout << map << endl;
lacksDMA balloon2(balloon);
cout << " balloon2 copy from balloon:\n";
cout << balloon2<<endl;
hasDMA map2;
map2 = map;
cout << "map2 = map,map2 is \n";
cout << map2<<endl;
return 0;
}
运行结果: