您的位置:首页 > 编程语言 > C语言/C++

C++中继承机制下基类public/private/protected成员的访问方式

2013-11-07 17:52 761 查看
C++中继承机制会让初学者感到十分的繁复和微妙,没有下面对基类中public/private/protected成员的访问方式做一个总结。首先这里涉及到几个复杂的情况:

1、一个继承类对象A对它自身所继承的来自于基类部分的数据成员的访问,这里是指基类的private和protected数据成员。

2、两个继承类对象A、B之间的相互的通讯(A访问B)。

3、一个继承类对象A与一个基类对象C之间的通讯,A访问C。

4、一个基类对象C与一个继承类对象A之间的通讯,C访问A。

例子来自Primer C++ 中的书店购书的管理系统。

基类:

class Item_base {
public:
Item_base(const std::string &book = "",
double sales_price = 0.0):
isbn(book), price(sales_price){}
std::string book() const { return isbn; }
virtual double net_price(std::size_t n) const
{return n * price; }
virtual ~Item_base(){ }
private:
std::string isbn;
protected:
double price;
};


基类的成员函数分别是构造函数Item_base,用来初始化书的isbn号和书的价格,book()函数,用来获取数的isbn号,net_price(n)函数,获取买了n本书之后需要支付的价格,这里因为不同总类的书有不同的打折方式,所以会有不同的支付策略,net_price以虚函数的形式出现在基类的Item_base中,在派生类中net_price函数重新实现。

下面来定义派生类。

class Bulk_item : public Item_base{
public:
double net_price(std::size_t) const;
private:
std::size_t min_qty;
double discount;
};
double Bulk_item::net_price(std::size_t cnt) const
{
if(cnt >= min_qty)
return cnt*(1-discount)*price;
else
return cnt*price;
}


net_price在基类中申明了是虚函数,在子类中重新定义了其价格策略。

一、

首先说明一下第一种情况,继承类对象A对自己所继承的protected和private成员的访问机制。如上面重新实现的函数net_price所示,我们可以看到A对继承的price成员用函数net_price进行直接访问操作。是否能对继承的私有的成员isbn进行直接范根操作呢。对象A将isbn修改,不想要通过基类构造函数初始化的isbn值。下面进行一下这个尝试,可以在继承类Bulk_item中定义一个函数

void change_isbn(std::string str);

void Bulk_item::change_isbn(string str)
{
isbn = str;
}




可以发现基类中的isbn成员无法在继承类对象中改变。isbn成员无法通过Bulk_item直接访问,那么要怎么访问呢?首先我们可以在这里推测,既然Bulk_item无法直接访问其所继承的private成员,是不是可以在基类中设置一个void change_isbn(std::string str)函数,在Bulk_item中设置一个void B_change_isbn(std::string str)成员函数,函数定义如下:

void B_change_isbn(string str)
{ change_isbn(str);}

Bulk_item b("C++ Primer", 40, 9, 0.1);
cout << b.book() << endl;
b.B_change_isbn("My C++ Primer");
cout << b.book() << endl;


输出结果:



嗯,我们的推测是正确的,继承类Bulk_item的成员A对自己所继承的protected、private和public访问机制就如上述,A不能直接访问继承的private的成员,要通过访问基类Item_base的成员函数来访问和操作其所继承的private成员,protected成员和public成员都可以直接进行访问操作。

二、

两个继承类对象A与B之间的相互通讯,A和B都是Bulk_item类对象,都继承了基类Item_base。

比如对象A进口若干本相同的书,对象B也进口了若干本相同的书,下面要比较A和B买的书,比较的项目如下:

a、A和B买的书是否相同,b、A和B买的书单价是否相同(在不同时候书的单价很变,比如同一本书,版本不同,书的单价会变),c、比较两者书打折的起点数量是否相同,d、比较两者的折扣是否相同。

这里我们不考虑友元函数,就把函数设置为Bulk_item类的成员函数,函数原型分别如下

bool isbn_same(const Bulk_item&)

bool price_same(const Bulk_item&)

bool min_qty_same(const Bulk_item&)

bool discount_same(const Bulk_item&)

假设我们的调用是A.isbn_same(B)、A.price_same(B)、A.min_qty_same(B)、A.discount_same(B),对于A.isbn_same(B),这里对象A需要深入到访问自己继承的private数据成员isbn,然后需要访问B继承的private数据成员isbn,由1的情况可知,这个时候A只能通过访问继承的book()来访问继承的私有成员isbn,A只能通过B继承的book()来访问B的isbn,然后再来比较二者的isbn是否一样。则函数定义如下:

bool Bulk_item::isbn_same(const Bulk_item&other_item)
{
return this->book() == other_item.book();
}

验证代码及结果如下:



A.price_same(B),price在Bulk_Item中属于继承的protected成员,A可以直接访问所继承的protected成员,B能直接访问自己所继承的protected成员,那么A是否可以直接和B所继承的protected成员进直接通信呢,换句话说,A.price_same函数是否能直接访问到B.price,下面来进行验证:

定义bool price_same(const Bulk_item&):

bool Bulk_item::price_same(const Bulk_item&other_item)

{

return this ->price == other_item.price;

}

运行结果如图:



所以说明相同的类,A可以通过自己的函数直接访问到B所继承的protected类。

下面来看最后的两个函数bool min_qty_same(const Bulk_item&)和bool discount_same(const Bulk_item&),成员A的函数是否能直接运用B的私有数据成员也就是A.min_qty_same()是否能直接操作B.min_qty。下面来进行验证:

首先定义min_qty_same(const Bulk_item&):

bool Bulk_item::min_qty_same(const Bulk_item&other_item)

{

return this->min_qty == other_item.min_qty;

}

运行结果如图:



这个是可以直接访问的。之前对于类的私有成员一直存在一个疑问,就是一个类的对象A的成员函数能不能直接在定义中使用相同类的一个对象B的私有数据成员。从这个例子可以看出,是可以的。再进行验证一下:

定义一个将一个Bulk_item对象的折扣策略改变成另外一个对象的折扣策略的函数:

void Bulk_item::change_discount(const Bulk_item&other_item)

{

this->discount = other_item.discount;

return;

}

运行结果:



C++ Primer中关于public和private数据成员的说法是:public成员可以被使用该类型的所有代码访问,private部分定义的成员可以被其他类成员访问,这个好理解。然后还有个说法是:使用类的代码不可以访问带有private标号的成员。从这个例子中我们可以知道,类一个对象的成员函数是可以直接使用相同类的另一个对象的私有成员的。

三、

一个继承类对象A和一个基类对象C之间的通信。

上一部分介绍了两个相同的继承类对象A和B之间的通信策略,这一部分来总结下一个继承类对象A访问一个基类对象C的情况。

假设A在书店买了几本书,知道它的书名、单价、能打折的最低购书数量以及折扣值,C也在书店买了几本书,C买的书没有任何打折,A是一个Bulk_item对象,C是一个Item_base对象,要比较A和C买的书是否相同以及他们的单价是否相同。如果在Bulk_item类中定义这个成员函数bool isbn_same(const Item_base&)和bool price_same(const
Item_base&),则我们定义的函数为:

bool Bulk_item::isbn_same(const Item_base&other_item)

{

return this->book() == other_item.isbn;

}

在vs中我们可以看到编译器中出现这样的错误提示:




说明继承类对基类对象的private数据成员是没有访问权限的。

bool Bulk_item::price_same(const Item_base&other_item)

{

return this->price == other_item.price;

}

在vs中编译器出现这样的错误提示:



说明Bulk_item类不能直接访问基类对象的protected成员。

四、Item_base对象对Bulk_item对象的访问,如果在Item_base中设置成员函数

bool isbn_same(const Bulk_item& other_item),直接访问other_item.isbn,编译器会显示无法访问other_item的private成员的错误提示。

bool price_same(const Bulk_item& other_item),这次也提示不行。

总结如下:

1、类自己在定义内部无法访问自己所继承的private成员,private成员不管是初始化还是其他的操作,都要通过继承的基类的函数进行操作访问,protected成员和public成员均可以访问。

2、两个相同的继承类对象之间的相互通讯,对于所各自所继承的private数据成员,双方都不能直接访问,要通过基类的函数进行操作,protected数据成员和自己本身非继承的private数据成员双方之间可以通过函数进行直接访问。

3、归根到底,基类和继承类是两个不同的类,基类对象和继承类对象不能直接访问对方的protected和private成员。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐