Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1073003
  • 博文数量: 77
  • 博客积分: 11498
  • 博客等级: 上将
  • 技术积分: 1840
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-04 11:10
文章分类

全部博文(77)

文章存档

2011年(1)

2010年(16)

2009年(5)

2008年(55)

分类: C/C++

2008-11-09 11:55:25


    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!


阅读(2028) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2008-11-09 21:49:45

太厉害了 学到了不少东西,感谢作者

chinaunix网友2008-11-09 15:08:37

谢谢分享。