【问题标题】:Designing A class with multiple set of method implementation [c++]设计具有多组方法实现的类 [c++]
【发布时间】:2015-10-08 15:46:52
【问题描述】:

我正在处理一个现有项目,该项目有一个类,我需要一个备用成员函数定义。我不想修改现有的成员函数或其签名,只是一个替代定义,必须根据一些 xml 文件选择运行时(编译时标志不是首选)。 我是 C++ 新手,所以这可能是一个愚蠢的问题。

请建议设计指南,这样我就不必更改和测试现有代码库,只需插入我的实现即可。

示例

class ABC{
public:
int operate(int, int);
}  
//Assume below method to be existing implementation
ABC::operate(int op1, int op2)
{
   return op1+ op2; //add
}

//Alternate desired implementation
ABC::operate(int op1, int op2)
{
   return op1 * op2; //multiply 
}

理想情况下,我希望上面是运行时选择,但如果这是唯一的方法,则可能会落入编译时间。

【问题讨论】:

  • 你已经尝试过了吗?欢迎提供一点草稿和更具体的内容。选择编译时 xml 文件究竟是什么意思?
  • 你希望如何在编译时读取 xml 文件?
  • 这完全取决于您使用的构建系统。例如,使用 makefile 是可行的。使用 Visual Studio IDE,我看不到一个简单的方法。
  • 由于不能在 C++ 代码内部完成,所以必须在编译器外部完成,类似于在编译前读取 xml 并更改编译的脚本,fe 通过将编译宏插入VS 项目文件。但我想知道在任何情况下这样的解决方案是否有意义。
  • ifswitch 语句是您根据某些运行时条件选择要执行的代码分支的方式。

标签: c++ design-patterns


【解决方案1】:

请注意此线程 Reason for C++ member function hiding 关于继承中的名称隐藏。

当派生类实现与基类中同名的NON VIRTUAL方法时,基类中的该方法将被隐藏,并且只能使用派生方法 - 通过静态对象类型派生。

我对你的建议是实现类似

class ABC{
public:
    int operate(int, int);
};  
//Assume below method to be existing implementation
ABC::operate(int op1, int op2)
{
    return op1+ op2; //add
}  

现在,对于您的扩展功能,从 ABC 派生(旁注:继承或组合是另一个讨论,请在 google 上阅读)。

class Derived : public ABC{
     operate(int op1, int op2){
          return op1 * op2; //multiply 
     }
}

现在,无论您需要什么新功能,将调用对象的静态类型更改为Derived,派生的operate 就会被调用。


如果可以将 ABC 的 operate 的签名更改为 virtual int operate(int,int);,则可能会出现更合乎逻辑的解决方案,然后可以发生多态,并且通过任何地方的引用类型访问 operate 将调用属于的 operate调用对象的动态类型。

因此,您只需要将对象实例化为Derived 类型而不是ABC

请注意,如果operate 是静态的,则无法使用虚拟方法,这里不清楚是否是这种情况。

【讨论】:

    【解决方案2】:

    我正在准备一个答案,但 Gulzar 同时回答了(他的答案结束)

    您需要的是 C++ 中称为 动态绑定 的基本概念/机制(也许您同时也学会了它,因为您的帖子已经 1 个月大)

        #include <iostream>
        #include <cstddef>
    
        using namespace std;
    
    
        class ABC_Base
        {
            public:
                //pure virtual member function
                //compelling effective creation of the
                //function in the daughter classes
                virtual int operate(int,int) = 0;
                //virtual xtor as base will be derived
                virtual ~ABC_Base() {}
        };
    
        class ABC_M1 : public ABC_Base
        {
            int operate (int a, int b ) {return a+b; }
        };
    
        class ABC_M2 : public ABC_Base
        {
            int operate (int a, int b ) {return a*b; }
        };
    
        ABC_Base * createABC(string xml_filename)
        {
            int criterion = 0;
    
            // nullptr need at least c++11 option
            ABC_Base * ptr = nullptr;
    
            //read xml file and update criterion
            //see other post to do that
            //criterion = ...
    
            switch(criterion)
            {
                case 0:
                    ptr = new ABC_M1();
                    break;
                case 1:
                    ptr = new ABC_M2();
                    break;
    
                default:
                    break;
            }
            return ptr;
        }
    
    
        int main()
        {
            ABC_Base * ptr = createABC("My_Config.xml");
    
            if (nullptr != ptr)
            {
                cout << ptr->operate(3,4) << endl;
            }
    
            // If you absolutely want / have to use plain old pointers
            // do not forget to release things
            // works even if ptr is null, so unconditional delete
            delete(ptr);
    
            return 0;
        }
    

    【讨论】:

    • 您还可以查看 vtable 和 vptr 的概念,了解动态绑定在内部是如何工作的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-23
    • 1970-01-01
    • 2011-04-12
    • 2021-08-29
    • 1970-01-01
    • 2011-05-22
    • 2012-02-25
    相关资源
    最近更新 更多