写了一个小程序来复习 基类和派生类 知识
※派生类中虚函数的声明(第 7.4 节)必须与基类中的定义方式完全匹配,但有一个例外:返回对基类型的引用(或指针)的虚函数。派生类中的虚函数可以返回基类函数所返回类型的派生类的引用(或指针)。例如,Item_base 类可以定义返回 Item_base* 的虚函数,如果这样,Bulk_item 类中定义的实例可以定义为返回 Item_base* 或 Bulk_item*。
※一旦函数在基类中声明为虚函数,它就一直为虚函数,派生类无法改变该函数为虚函数这一事实。派生类重定义虚函数时,可以使用 virtual 保留字,但不是必须这样做。
1.item_base.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
class item_base
{
public:
explicit item_base( const string &isb = "base" , const double &pri = 1.0);
/*
• 继承层次的根类一般都要定义虚析构函数。
• 除了构造函数之外,任意非 static 成员函数都可以是虚函数。
保留字只在类内部的成员函数声明中出现,不能用在类定义体
外部出现的函数定义上。
*/
virtual ~item_base(void);
/* 友元关系不能继承 */
friend class frnd;
public:
virtual double net_price( size_t & ) const;
// virtual void print_total( ostream &os , const item_base &item ,size_t n ) const;
string book() const;
private:
string isbn;
protected:
/*
• 像 private 成员一样,protected 成员不能被类的用户访问。
• 像 public 成员一样,protected 成员可被该类的派生类访问。
*/
double price;
/*
如果基类定义 static 成员(第 12.6 节),则整个继承层次中只
有一个这样的成员。无论从基类派生出多少个派生类,每个 static
成员只有一个实例。static 成员遵循常规访问控制:如果成员在基
类中为 private,则派生类不能访问它。
*/
static double price_rate;
};
2.item_base.cpp
#include "item_base.h"
double item_base::price_rate = 0.0;
item_base::item_base( const string &isb, const double & pri ):
isbn(isb) , price( pri ){
// cout << " in base constructor." <<endl;
}
item_base::~item_base(void){
// cout << " in base destructor." <<endl;
}
double item_base::net_price( size_t &n) const{
cout << " in base price." <<endl;
return n*price;
}
string item_base::book() const{
return isbn;
}
//void item_base::print_total( ostream &os ,const item_base &item ,size_t n ) const{
// cout << " in base print." <<endl;
//
// os << " ISBN: " << item.book() << endl;
// os << " total price : " <<item.net_price(n) <<endl;
//}
3.bulk_item.h
#pragma once
#include "item_base.h"
/*
1. C++允许多重继承,例如 class item : public base1, base2...
2. 声明一个包含派生列表的类(而不实现)是错误的。
class item: public base;
3. 函数可以设定默认默认参数,默认参数定义的顺序为自右到左。即如果一个参数设定了
缺省值时,其右边的参数都要有缺省值
4. c++三种继承方式:public, private, protected 假设B类继承A类,即B类是A类的直接子类。
public继承:A的访问属性在B类保持不变。
A的public-----------B仍是public;
A的protected-------B仍是protected;
A的private----------B无法访问(仍是private);
protected继承:
A的public-----------B变成protected;
A的protected-------B仍是protected;
A的private----------B无法访问(仍是private);
private继承:
A的public-----------B无法访问(变成private);
A的protected-------B无法访问(变成private);
A的private----------B无法访问(仍是private);
*/
class bulk_item :public item_base{ //不加public 默认是private继承
public:
explicit bulk_item(const size_t &qty = 10 , const double &disc = 0.2/*,
const string &isb = "derived" , const double &pri = 2.0*/);
/*
派生类一般会重定义所继承的虚函数。派生类没有重定义某个虚函数,
则使用基类中定义的版本。
*/
~bulk_item(void);
public:
/*
原则上子类重写父类虚函数时声明和定义要于父类完全一致,但有一个
例外:虚函数返回值是父类的指针或引用 可以在子类中将返回改成子类
的指针或引用:比如父类有虚函数:base *test(); 子类可重写成: item *test();
*/
/*virtual*/ double net_price( size_t & ) const;
// virtual void print_total( ostream &os ,const item_base &item ,size_t n ) const;
void memfcn(const bulk_item &d, const item_base &b);
private:
size_t min_qty;
double discount;
};
4.bulk_item.cpp
#include "bulk_item.h"
bulk_item::bulk_item(const size_t &qty , const double &disc /*, const string
&isb , const double &pri*/)
:discount(disc) , min_qty(qty) /*, isbn(isb) , price(pri)*/
{
}
bulk_item::~bulk_item(void)
{
}
void bulk_item::memfcn(const bulk_item &d, const item_base &b)
{
// attempt to use protected member
double ret = price; // ok: uses this->price
ret = d.price; // ok: uses price from a Bulk_item object
/* 派生类只能通过派生类对象访问其基类的 protected 成员,
派生类对其基类类型对象的 protected 成员没有特殊访问权限。*/
//ret = b.price; // error: no access to price from an Item_base\
/* 派生类可以访问本身protected 和基类(非对象)的protected 成员 */
ret = bulk_item::price; // ok: uses price from a Bulk_item class
ret = item_base::price; //ok: uses price from a Bulk_item class
// item_base::isbn; //error C2248: “item_base::isbn”: 无法访问 private 成员
//(在“item_base”类中声明)
/* ok , 说明派生类也会继承基类的静态数据成员 */
double rate1 = bulk_item::price_rate;
double rate2 = price_rate;
}
double bulk_item::net_price( size_t &cnt ) const {
cout << " in derived price." <<endl;
if( cnt > min_qty )
return cnt * ( 1- discount ) * price;
else
return cnt * price;
}
//void bulk_item::print_total( ostream &os ,const item_base &item ,size_t n ) const{
// cout << " in derived print." <<endl;
//
// os << " ISBN: " << item.book() << endl;
// os << " total price : " <<item.net_price(n) <<endl;
//}
5.frnd.h
#pragma once
//#include "item_base.h"
#include "bulk_item.h"
class frnd
{
public:
frnd(void);
~frnd(void);
public:
string visit_base_isbn( const item_base &bas) {
return bas.isbn;
}
double visit_base_price( const item_base &bas){
return bas.price;
}
double visit_derived_price( const bulk_item &bukl){
return bukl.price;
}
};
6.frnd.cpp
#include "frnd.h"
frnd::frnd(void)
{
}
frnd::~frnd(void)
{
}
7.main.cpp
#include <iostream>
#include "item_base.h"
#include "bulk_item.h"
#include "frnd.h"
using namespace std;
void print_total( ostream &os ,const item_base &item ,size_t n ) {
//cout << " \nin base print." <<endl;
os << " ISBN: " << item.book() << endl;
/* 通过引用或指针调用虚函数时,编译器将生成代码,
在运行时确定调用哪个函数,被调用的是与动态类型相对应的函数。*/
os << " total price : " <<item.net_price(n) <<endl;
}
int main(int argc, char **argv){
item_base base ;
bulk_item derived;
/* 测试动态绑定,动态绑定需要符合两个条件:调用函数必须是virtual ;必须
要通过指针或引用调用虚函数。 动态绑定时执行函数取决于实际执行的类
型,而不取决于指针或引用变量类型。形参为基类类型的引用 */
print_total( cout , base , 50 );
print_total( cout , derived , 50);
/* 测试指针 将基类类型的引用或指针绑定到派生类对象对基类对象
没有影响,对象本身不会改变,仍为派生类对象。*/
item_base *pbase = &base ;
item_base &rbase = base;
item_base *pderived = &derived;
item_base &rderived = derived;
size_t cnt = 20;
/* 调用基类的net_price */
base.net_price(cnt); pbase->net_price(cnt); rbase.net_price(cnt);
/* 调用派生类的 net_price */
derived.net_price(cnt); pderived->net_price(cnt); rderived.net_price(cnt);
//double pri = item_base::price; //error C2597: 对非静态成员“item_base::price”的非法引用
//pri = bulk_item::price; //error C2653: “bulk_item”: 不是类或命名空间名称
/* 测试继承的类型(接口继承和实现继承)带来的影响:
1. class bulk_item :public item_base
2. class bulk_item :protected item_base ----error C2247: “item_base::book”不可访问,因为
“bulk_item”使用“protected”从“item_base”继承
3. class bulk_item :private item_base ----error C2247: “item_base::book”不可访问,因为
“bulk_item”使用“private”从“item_base”继承
*/
derived.book();
/* 测试友元 */
frnd fnd;
fnd.visit_base_isbn(base);
fnd.visit_base_price(base);
fnd.visit_derived_price(derived);
system("pause");
return 0;
}