【问题标题】:Reducing parent-child class code duplication减少父子类代码重复
【发布时间】:2012-08-28 06:15:55
【问题描述】:

我遇到了多态性和父子关系的问题。采取以下两个类,并想象在我的应用程序中我创建了一个“孩子”对象。在对象之外,我调用的唯一函数是 update(),它反过来调用对象中我需要的所有其他内容。在这一系列调用中,“父”和“子”中唯一不同的函数是 dosomething2()。

class parent 
{
    public:
        void dosomething1() {}; //amongst other things, calls dosomething2
        void dosomething2() {};
        void update() {}; //amongst other things, calls dosomething1
}

class child : public parent
{
    void dosomething2() {}
}

我意识到如果我创建一个 'child' 对象并调用 update(),则只会调用父类函数。我不得不将 update() 和 dosomething1() 复制到子类,然后一切都按预期工作。这不是一个很好的解决方案,因为有很多重复的代码 - 有没有办法改进这个?

更新: 感谢提供的答案,我使用虚拟 dosomething2() 函数更新了父类。现在调用了正确的函数,我不必将 dosomething1() 复制到子类。不幸的是,如果我不将 update() 复制到子类,则会出现符号查找错误(父子类都在一个库中)。

class parent 
{
    public:
        void dosomething1() {}; //amongst other things, calls dosomething2
        virtual void dosomething2() {};
        void update() {}; //amongst other things, calls dosomething1
}

class child : public parent
{
    void dosomething2() {}
    /*void update() {}; //symbol lookup error if this is left uncommented */
}

更新2 符号查找错误与代码无关。我做了一个 make clean,然后 make(它构建了一个 .so 库和可执行文件),现在一切都按预期工作了。

【问题讨论】:

    标签: c++ oop parent-child


    【解决方案1】:

    您没有将基类中的函数标记为虚拟:

    class parent 
    {
        public:
            virtual void dosomething1() {}; //amongst other things, calls dosomething2
            virtual void dosomething2() {};
            void update() {}; //amongst other things, calls dosomething1
    }
    

    另外,仅供参考,您正在做的事情称为template method pattern

    【讨论】:

    • 如果没有在子类中重新定义 dosomething1() 是否必须是虚拟的?
    • 我现在在 update() 上遇到符号查找错误(我没有在问题中提到父母和孩子在图书馆中,因为我认为这没有区别) -知道为什么吗?
    • @akid 它必须是虚拟的才能使多态性起作用。如果那是您的代码(在标题中实现),链接器不应该抱怨
    • 我是否将其声明为虚拟似乎并没有什么不同(在标头中声明的函数,在代码文件中定义)。
    • @akid 您是否将文件链接在一起?可能不会。
    【解决方案2】:

    如果你想要dynamic-polymorphism,你应该在父类中使用关键字virtual。然后在子类中重新实现或不重新实现虚函数。

    class parent 
    {
        public:
            void dosomething1() {}; //amongst other things, calls dosomething2
            virtual void dosomething2() {};
            void update() {}; //amongst other things, calls dosomething1
    }
    

    【讨论】:

    • 在引入 virtual 关键字后,我在 update() 上遇到符号查找错误(我没有在问题中提到父母和孩子在图书馆中,因为我认为它不会不同) - 知道为什么吗?
    【解决方案3】:

    您应该将相关功能设为virtual。假设您希望从对 update() 的调用中调用 childdoSomething1()doSomething2()

    class parent 
    {
        public:
            virtual void dosomething1() {}; //amongst other things, calls dosomething2
            virtual void dosomething2() {};
            void update() {}; //amongst other things, calls dosomething1
    }
    
    class child : public parent
    {
        virtual void dosomething2() {}
    }
    

    然后,对childupdate() 的调用将调用派生类的方法(如果可用)。请注意update() is not virtual, so you should have no filed calledupdateinchild`,否则您将隐藏该名称。

    【讨论】:

    • 在这个例子中没有必须,但在实际案例中很可能是必要的。
    • 一般情况下,在使用模板方法模式时,不要重写描述算法的方法。
    • @LuchianGrigore 我知道,但 OP 并没有说明模板方法。据我所知,他们最终也会隐藏update 方法。
    • 保护它是很常见的,是的。
    • 孩子没有自己的 doSomething1()。我想要的顺序是 parent:update()->parent:doSomething1()->child:doSomething2()。顺便说一句,我从别人那里得到了父类,并正在用孩子扩展它。我同意“受保护”声明,一旦我开始工作,它就在我的待办事项清单上。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-30
    • 2016-07-24
    相关资源
    最近更新 更多