代码之家  ›  专栏  ›  技术社区  ›  elcuco

将叶类重构为基类,并将其保留为接口实现

  •  1
  • elcuco  · 技术社区  · 14 年前

    我正在尝试重构一个工作代码。代码基本上是将接口类派生到工作实现中,我希望在原始项目之外将此实现用作独立类。

    但是,我不想创建fork,我希望原始项目能够拿出它们的实现,并使用我的。问题是,层次结构是非常不同的,我不知道这是否会工作。我也不能在我的项目中使用原始的基类,因为实际上它在项目中很纠结(太多的类,包括),我只需要处理原始项目的问题的一个子域。

    我写这段代码是为了测试如何实现这一点,虽然它在工作,但我不确定我是否喜欢它:

    #include <iostream>
    
    // Original code is:
    // IBase -> Derived1
    
    // I need to refactor Derive2 to be both indipendet class
    // and programmers should also be able to use the interface class
    // Derived2 -> MyClass + IBase
    // MyClass
    
    
    class IBase {
    public:
        virtual void printMsg() = 0;
    };
    
    ///////////////////////////////////////////////////
    class Derived1 : public IBase {
    public:
        virtual void printMsg(){ std::cout << "Hello from Derived 1" << std::endl; }
    };
    
    
    //////////////////////////////////////////////////
    class MyClass {
    public:
        virtual void printMsg(){ std::cout << "Hello from MyClass" << std::endl; }
    };
    
    class Derived2: public IBase, public MyClass{
        virtual void printMsg(){ MyClass::printMsg(); }
    };
    
    class Derived3: public MyClass, public IBase{
        virtual void printMsg(){ MyClass::printMsg(); }
    };
    
    int main()
    {
        IBase *o1 = new Derived1();
        IBase *o2 = new Derived2();
        IBase *o3 = new Derived3();
        MyClass *o4 = new MyClass();
    
        o1->printMsg();
        o2->printMsg();
        o3->printMsg();
        o4->printMsg();
    
        return 0;
    }
    

    输出工作如预期(使用GCC和CLAN测试,2种不同的C++实现,所以我认为我在这里是安全的):

    [elcuco@pinky ~/src/googlecode/qtedit4/tools/qtsourceview/qate/tests] ./test1
    Hello from Derived 1
    Hello from MyClass
    Hello from MyClass
    Hello from MyClass
    [elcuco@pinky ~/src/googlecode/qtedit4/tools/qtsourceview/qate/tests] ./test1.clang 
    Hello from Derived 1
    Hello from MyClass
    Hello from MyClass
    Hello from MyClass
    



    问题是

    我最初的代码是:

    class Derived3: public MyClass, public IBase{
        virtual void IBase::printMsg(){ MyClass::printMsg(); }
    };
    

    这是我想表达的,但这不是编译。我必须承认我不完全理解为什么这个代码可以工作,因为我期望新方法 Derived3::printMsg() 将实现 MyClass::printMsg() 而不是 IBase::printMsg() (即使很艰难,这也是我想要的 想要)。

    当两个“姊妹类”具有相同的虚拟函数名时,编译器如何选择要重新实现的方法?

    如果有人有更好的方法来实现这一点,我也想知道:)

    2 回复  |  直到 13 年前
        1
  •  1
  •   Alex B    14 年前

    答案是,编译器重写 二者都 函数,如本示例所示:

    #include <cstdio>
    using std::printf;
    
    class A {
    public:
        virtual void a() {
            printf("A::a\n");
        }
    };
    class B {
    public:
        virtual void a() {
            printf("B::a\n");
        }
    };
    class C : public A, public B {
    public:
        virtual void a() {
            printf("C::a\n");
            A::a();
            B::a();
        }
    };
    int main() {
        C c;
        A &a = c;
        B &b = c;
        printf("Calling C::a via A\n");
        a.a();
        printf("Calling C::a via B\n");
        b.a();
    }
    

    Calling C::a via A
    C::a
    A::a
    B::a
    Calling C::a via B
    C::a
    A::a
    B::a
    

    如果要覆盖其中一个而不是另一个,则需要重命名它。它不仅会做你想做的,而且会更清晰。

        2
  •  0
  •   Troubadour    14 年前

    编译器实际上并没有选择要重写的两个方法之一。相反,它发现有两个具有相同签名的虚拟函数,并在派生类中查找该签名的重写。

    如果 Derived3 printMsg 衍生3 会很含糊。因为您已经重新实现了该方法,编译器可以愉快地、明确地在类型为的对象上调用该版本 衍生3 .