2006年10月1日星期日

C++类继承中的几个小问题

是的,我一直是个Delphi的粉丝。虽然现在工作上用的是C++(而且是在用VC/MFC),但一直都没有认真去学习它。前两天听俺们项目组的C ++高手讲解了一些“基本知识”,我还是觉得这个语言太复杂了,陷阱也太多。以下有几个例子(鄙人C++确很粗浅,如有不对的地方,敬请指正)。

[@more@]

第一个例子:

class Base
{
public:
virtual void MethodFoo(std::string s);
}
class Child: public Base
{
public:
virtual void MethodFoo(std::string s);
}
Base *b = new Child;
std::string s("something");
b.MethodFoo(str);

我 们会利用多态性来调用不同的MethodFoo实现,但突然有一天你觉得MethodFoo中间s是不应该发生变化的,于是加了一个const。问题来 了,很多编译器不会告诉你任何告警,但b.MethodFoo再也调用不到派生类的MethodFoo了,除非你把它们一个个都改过来。

第二个例子:

class Base
{
public:
virtual void MethodFoo(std::string s);
}

class Child: public Base
{
public:
virtual void MethodFoo(std::string s);
{
DoSometingMyself();
Base::MethodFoo(s);
}
}

突然有一天,你觉得这个设计不太合理,需要在Base和Child之间再插入一层(class Middle),这就意味着你得修改Child所有函数中类似上面黑体的部分,把它们改成Middle::MethodFoo什么的。

第三个例子:

我 们知道C++中支持多继承,但它对于多个基类中有同名同类型函数的问题没有提供解决方法(也许你会说,我们不应该写这样的代码,但仔细想想X, Y都是接口(C++用纯虚类来做)的情况下,难免会有重名的)。对于X, Y均派生自B,而C又牌证自X+Y这种”恐怖的菱形,它有一个"workaround"是用虚基类,但这要求更改X, Y的代码,使得它们虚拟继承自B。

-----------

是的,这三个问题在Delphi中均可以避免:

1. 要重新实现虚方法必须用override关键字;而带有override声明的方法如果参数不一致,编译器会报错;如果基类中不存在叫这个名字的方法,也会报错。而你确实要用同样的函数名做别的事情,得用reintroduce或者overload关键字。

2. Child::MethodFoo中调用其父类的MethodFoo时不用写Base::MethodFoo,直接写inherited MethodFoo就行了。

3. 采用方法分辨子句即可:

TChild = class(TParent, Interface1, Interface2)
procedure Interface1.MethodFoo = MethodFoo1;
procedure Interface2.MethodFoo = MethodFoo2;
procedure MethodFoo1(s: String);
procedure MethodFoo2(s: String);
end;

没有评论: