覆盖虚函数 - 派生类具有不同的参数

时间:2017-04-18 06:14:57

标签: c++ ooad

我们说我们有以下两个班级

class Base {
public:
    virtual ~Base();
    virtual void op(string& s1) = 0;
};

class Derived1 : public Base {
public:
    virtual void op(string& s1) override;
};
到目前为止,这么好。现在,需要一个新的要求 创建Derived2类,但是这个类需要2个字符串 作为op虚函数中的args。当然,如果我添加功能op 在Derived2中有2个字符串作为输入,它被重载而不是覆盖。 所以,我必须做一些像 -

class Base {
public:
    virtual ~Base();
    virtual void op(string& s1) {}
    virtual void op(string& s1, string& s2) {}
};

class Derived1 : public Base {
public:
    virtual void op(string& s1) override;
};

class Derived2 : public Base {
public:
    virtual void op(string& s1, string& s2) override;
};

这样可行,但我被迫在Base类中添加第二个op函数。 此外,Base类函数现在不是纯虚拟的,这是 否则派生类需要实现不必要的 操作功能。这对我来说似乎有些愚蠢。

现在,如果新要求导致我们创建Derived3,则需要创建Derived3 op函数的不同参数集,我们需要再添加一个 基类中的op函数。理想情况下,基类不应该改变 有人添加了一个新的派生类。

我确信有更好的方法可以做到这一点。很确定有一个 设计模式,因为这似乎是一个常见的问题和 必须已经解决了。

有什么建议吗?

谢谢, Amarnath

2 个答案:

答案 0 :(得分:0)

如果你有多个派生类并不“行为”相同(例如,对于不同的派生类有不同数量的参数),你有两个选择(有一些变化):

  1. 在基类中为所有变体实现虚函数。

  2. 你的班级hieararchy不是“干净”,你可能需要“知道”在某些情况下它是哪种类型。使用dynamic_cast(或您自己的类型检测机制,如在LLVM项目中,具有llvm::dyn_cast

  3. 考虑一下:

    vector<Base*> v;
    
    ... insert derived types in v ... 
    
    for(auto i : v)
    {
        v->op( ??? ) 
    }
    

    如果op是1,2或3个参数,代码如何知道?它不能,对吧?因此,您的选择是询问班级op需要多少参数,并始终使用相同的数字(例如,op("abc", "", "");将用于Derived1op("abc", "def", ""); Derived2op("abc", "def", "ghi");Derived3class Base { public: virtual ~Base(); virtual void op(string& s1) = 0; virtual void op(string& s1, string &s2) = 0; ... for as many string arguments you need ... virtual int num_strings() { return 0; } }; class Derived1 : public Base { public: virtual void op(string& s1) override; virtual int num_strings() override { return 1; } }; class Derived2 : public Base { public: virtual void op(string& s1, string& s2) override; virtual int num_strings() override { return 2; } };

    或者你可能有类似的东西:

    for(auto i : v)
    {
        switch(v->num_strings())
        {
        case 1:
            v->op(s1);
            break;
        case 2:
            v->op(s1, s2);
            break;
        default:
            ... some handling of unknown number ....
        }
    }
    

    现在我们可以实现我们的通用(-ish)循环:

    llvm::dyn_cast

    这里的关键是,如果你要对从同一个基类派生的所有对象“做”同样的事情,他们必须拥有相同的接口。

    在我拥有的编译器项目中,我在需要时使用if,因为基类有许多泛型操作,但并非ALL操作在所有派生类上都可用,因为这会使基类成为基类拥有大量完全没用的成员函数 - for不必具有与if循环相同的操作,并且赋值不需要for的任何内容。需要1}}或op(vector<string>& sv)循环。

    编辑:在准备好继续这一天的同时,我想到了另一个解决方案,在某些情况下可能是正确的:使用imap <LeftMouse>i而不是1,2,3或n个参数。

    与许多事情一样,如果不进一步了解确切的问题,正确的解决方案并不总是很明确。

答案 1 :(得分:0)

从Mats回答并使用c ++初始化列表构造函数的正确方法可以是(在调用op functon时注意括号{}):

#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Base {
public:
    virtual ~Base() { };
    virtual void op(const std::vector<string>& s1) {std::cout<<"Base..."<<s1.at(0)<<std::endl;}
   // virtual void op(const stdstring& s1, const string& s2) {std::cout<<"Base..."<<s1<<" "<<s2<<std::endl;}
};

class Derived1 : public Base {
public:
    virtual void op(const std::vector<string>& s1) override {std::cout<<"Derived1..."<<s1.at(0)<<std::endl;}
};

class Derived2 : public Base {
public:
    virtual void op(const std::vector<string>& s1) {std::cout<<"Derived2..."<<s1.at(0)<<std::endl;}
};
int main()
{
    Base *ptr= new Derived2();
    ptr->op({std::string("Test1"),std::string("Test2")});

}