试题:两个基类有同名的虚函数要实现, 怎么办?

来源:互联网 发布:mac 查看照片拍摄日期 编辑:程序博客网 时间:2024/06/14 18:25
先把问题陈述一下:

有两个类A, B, 它们可能是别人实现的(或是别人提供的库中的类), 很复杂且已经在用, 你不能修改他们, 你想写一个类C同时具有这两个类的特性, 因为自己实现它代价实在是太大, 所以你想到用C继承A, B以达到效果, 但是有一个问题, A, B具有一个同名的虚函数, 你在C中怎么重新实现这个虚函数呢? 先看下面的代码:

#include <string>#include <iostream>using namespace std;class ChineseName{public:    virtual string getname()    {        return string();    }};class EnglishName{public:    virtual string getname()    {        return string();    }};class Name : public ChineseName, public EnglishName{public:    virtual string getname()    {        return string("chinese or english name? I donot know");    }};int main(){    Name n;    ChineseName & c = n;    EnglishName & e = n;    cout << n.getname() << endl;    cout << c.getname() << endl;    cout << e.getname() << endl;    return 0;}

三个输出都是一样的, 可是我怎么才能在c.getname()中输出中文名, e.getname()中输出英文名呢, 最根本的问题是我只能在Name中实现一个getname(), 但是它却被要求有两个功能, 分别输出中文名和英文名, 这着实没办法

"计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决",现在我们就通过增加两个中间类来试试

我们用两个抽象类来分别继承ChinessName和EnglishName, 它们分别重新实现getname(), getname()的实现方式相同, 都是通过NVI手法来做的(尽管getname()不是non-virtual函数), 它们分别调用两个非同名的纯虚函数, 然后再让Name继承这两个中间类, 具体实现看代码:

#include <string>#include <iostream>using namespace std;class ChineseName{public:    virtual string getname()    {        return string();    }};class EnglishName{public:    virtual string getname()    {        return string();    }};class ICName : public ChineseName{public:    virtual string getname()    {        return getChineseName();    }private:    virtual string getChineseName() = 0;};class IEName : public EnglishName{public:    virtual string getname()    {        return getEnglishName();    }private:    virtual string getEnglishName() = 0;};class Name : public ICName, public IEName{private:    virtual string getChineseName()    {        return string("二斗墨汁");    }    virtual string getEnglishName()    {        return string("Adward Ink");    }};int main(){    Name n;    ChineseName & c = n;    EnglishName & e = n;//  cout << n.getname() << endl;    cout << c.getname() << endl;    cout << e.getname() << endl;    return 0;}

上面的代码运行可以分别得到中文名和英文名, 但你也应该看到这句注释掉的代码: cout << n.getname() << endl; 是的, 它不能通过编译, 它会产生二义性, 因为它不知道调用的是从ICName还是从IEName继承下来的getname(), 但为什么第一份代码又可以呢? 其实我当初也以为会产生二义, 谁知没有, 不过从测试上分析, 可知: 一份getname()已经重写了两个基类的getname()的实现

如上我们可以用Name对象直接调用ChineseName和EnglishName中所有除getname()以为的功能接口, 如果我们想分别想得到中文名和英文名怎么办? 方法一同上代码, 先转化为对应基类的引用再调用getname(), 方法二把getChineseName()和getEnglishName()改成公有的, 直接调用这两个函数

第二份代码的实现, 得助于从网上得来的一份华为学习资料(几年前看资料学过来的技术, 原资料也被遗弃了), 感谢华为