is-a and has-a,any more?

    is-a and has-a,any more?
    作者:tyc611.cublog.cn,2008-11-9
相信任何一本合格的C++教程上都有“is-a”和“has-a”的叙述,却没看到有书提及“is-implemented-in-terms-of”。

如果对C++有一定的了解,应该知道public继承表达的是“is-a”关系,而组合(把另一个类对象作为数据成员)表达的是“has-a”关系,但protected/private继承呢?事实上,proteced/private继承表达的就是“is-implemented-in-terms-of”关系。public继承和protected/private继承的这点区别导致了它们的使用相当的不同:“is-a”关系(B is-a A)表明B对象可以当作A使用,而“is-implemented-in-terms-of”关系(B is-implemented-in-terms-of A)只表明B是根据A实现的,但不能够 直接把B当作A来使用。下面举例说明:

class A
{
};

class B: public A
{
};

class C: protected A
{
};

class D: private A
{
};

void func(const A&)
{
}

B b;
func(b);            // ok

C c;
func(c);            // error, c is "NOT" A!
func((const A&)c);  // ok, explicit conversion

D d;
func(d);            // error, d is "NOT" A!
func((const A&)d);  // ok, explicit conversion

try {
    throw B();
}
catch (const A&) {
    // ok, the exception will be caught
    cout << "catch A" << endl;
}

try {
    throw C(); // or throw D();
}
catch (const A&) {
    // unlucky, the exception will NOT be caught!
    cout << "catch A" << endl;
}
catch (...) {
    cout << "catch all" << endl;
}

看到了没,B是A的public派生类,因此可以把B用在需要A的地方,而C和D是A的protected和private派生类,不能够直接用于需要A的地方!但本质上C和D对象仍然是一个A对象,所以可以通过显示类型转换来达到目的。

为什么有此区别呢?下面从语言来深入探讨这个问题。

如果你编译上面的程序,func(c)和func(d)调用将会产生类似编译错误:
error: 'A' is an inaccessible base of 'C'
error: 'A' is an inaccessible base of 'D'

不难理解上面的错误提示,原因是 A不是C或D的可访问基类,从而找到了此问题的语言线索。那么,什么是“可访问基类”呢?标准11.2(Accessibility of base classes and base class members)给出了我们需要的答案。

[quote]
11.2.4
...A base class is said to be accessible if an invented public member of the base class is accessible. If a base class is accessible, one can implicitly convert a pointer to a derived class to a pointer to that base class (4.10, 4.11). [Note: it follows that members and friends of a class X can implicitly convert an X* to a
pointer to a private or protected immediate base class of X. ]...

11.2.3
...a conversion from a pointer to a derived class to a pointer to an inaccessible base class might be ill-formed if an implicit conversion is used, but well-formed if an explicit cast is used. ...
[/quote]

对上面的这段话解释一下:
1. 当基类的public成员可访问时,那么此时基类就是可访问基类。由此,我们可以推出:假如类B继承自类A(不论何种继承),(1)如果是public继承,那么在任何地方A都是B的可访问基类;(2)在类B的成员函数和友元函数中,A也是B的可访问基类(不论何种继承);(3)在类B外,如果是private/protected继承,则A 不是可访问基类。
2. 对于可访问基类,可以隐式地把派生类指针或引用转换为基类指针或引用;但对于不可访问基类,
只能通过显示类型转换。

回到前面的例子,由于在func(c)和func(d)调用时,类A是类C和D的不可访问基类,因此不能隐式转换为A,但可以显示转换。

Ok, that's all. Hope you guys will enjoy it!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值