【问题标题】:Can derived class have two sets of virtual functions?派生类可以有两组虚函数吗?
【发布时间】:2013-05-10 22:26:35
【问题描述】:

是否可以让派生类拥有两组与基类相同的虚函数?我正在寻找类似以下的东西。能够在两组函数指针之间进行选择的想法。

class Base
{
    virtual void func1;
    virtual void func2;
};

class Derived: Base
{
    float somemember;

    void somefunction()
    {
        Base* func = this->derived_functions1;
    }
    class derived_functions1
    {
        virtual void func1()
        {
           return somemember*100;
        }
        virtual void func2;
    };
    class derived_functions2
    {
        virtual void func1;
        virtual void func2;
    };
};

【问题讨论】:

  • 我相信您只是在创建两个派生,它们应该是单独的类。也许你需要额外的类来聚合它们并选择合适的类。根据你的推理,不能说太多。

标签: c++ function-pointers virtual-functions


【解决方案1】:

简短回答:不能。一个类只能重写一次继承的虚函数。

但是,有一种设计模式可以动态交换函数的行为,称为策略模式。简而言之:具有可交换行为的类有一个指向 Strategy 基类的指针,该基类定义了该行为的接口。它填充了具体的策略类。具有不同行为的函数只是将其调用委托给 Strategy 指针。这是一个针对您的问题量身定制的示例:

class Base {
public:
    virtual void func1() = 0;
    virtual void func2() = 0;

    virtual ~Base(){}
};

#include <iostream>
#include <memory>

class Derived : public Base
{
  struct F1Strategy { 
    virtual void f1Impl() = 0; 
    virtual ~F1Strategy() {}
  };

  struct Impl1 : F1Strategy {
    void f1Impl() override { std::cout << "one!\n"; }
  };

  struct Impl2 : F1Strategy {
    void f1Impl() override { std::cout << "two?\n"; }
  };    

  std::unique_ptr<F1Strategy> f1Strategy;
public:
  Derived() 
    : f1Strategy(new Impl1())
  {}

  void func1() override { f1Strategy->f1Impl(); }

  void func2() override { 
    static std::unique_ptr<F1Strategy> otherStrategy(new Impl2());
    f1Strategy.swap(otherStrategy);
  }
};

int main() {
  std::unique_ptr<Base> pb(new Derived());
  pb->func1();  //  ==> one!
  pb->func2();  //swap
  pb->func1();  //  ==> two?
  pb->func1();  //  ==> two?
  pb->func2();  //swap
  pb->func1();  //  ==> one!
}

查看实际操作:http://ideone.com/zk3UTI

【讨论】:

    【解决方案2】:

    在本例中,它不会编译,因为 derived_function1derived_functions2 不是从 Base 继承的。

    但你可以有这样的东西:

    class Base
    {
        virtual void func1();
        virtual void func2();
    };
    
    class Wrapper    {
      public:
        Wrapper(int arg)
        {
            switch(arg)
            {
            case 1:
                b = new derived_functions1;
                break;
            case 2: 
                b = new derived_functions2;
                break;
            default:
                cout << "bad value of arg" << arg << endl;
                exit(1);
            }
        }
     ~Wrapper()
     {
        delete b;
     }
     Base* GetClass()
     {
        return b;
     }
     private:
        Base *b;
    
        class derived_functions1: public Base
        {
            virtual void func1();
            virtual void func2();
        };
        class derived_functions2: public Base
        {
            virtual void func1();
            virtual void func2();
        };
    };
    

    【讨论】:

    • 我已经编辑了代码以使其更安全(并希望编译)。我的意思是用一种简单的方式来展示这个概念。
    【解决方案3】:

    不是你做的那样。但是你可以让内部的class derived_functionsX 成为它们的public: Base,而不是让你的主要Derived 包含一个std::unique_ptr&lt;Base&gt; ptr你可以设置为new derived_functions1new derived_functions2 并在Derivedfunc1func2中实现调用ptr-&gt;func1()ptr-&gt;func2()

    要使所有这些正常工作,Base 还必须有一个 virtual ~Base() {},否则无法正确删除。

    【讨论】:

      【解决方案4】:
      class Base
      {
      public:
          virtual void func1();
      
          virtual ~Base(){}
      };
      
      struct Impl1 : Base
      {
          void func1() override {}
      };
      
      struct Impl2 : Base
      {
          void func1() override {}
      };
      
      struct Derived :  Base
      {
          Derived(std::unique_ptr<Base> implementation) :
              impl(std::move(implementation))
          {}
      
          void func1() override { impl->func1(); }
      
          void changeImpl(std::unique_ptr<Base> implementation)
          {
              impl = std::move(implementation);
          }
      
      private:
          std::unique_ptr<Base> impl;
      };
      

      【讨论】:

      • Base 还必须有虚拟析构函数,否则unique_ptr&lt;Base&gt; 无法正确删除 ImplX。
      • 嗯,....实际上它可以正确删除它们,因为 unique_ptr 设置了一个内部“删除器”,以接收对象的类型为模板。但是拥有一个虚拟 dtor 可以使 unique_ptr 实现从一个更简单、更“节省空间”的实现中选择。这主要取决于 unique_ptr 实现的智能程度。无论如何,最好不要冒险
      • 是的,具有虚函数的基类应该总是有一个虚 dtor。
      • 谢谢大家的帮助!这些仿函数是否能够访问派生类的成员?我在派生类中编辑了 func1 以反映我正在寻找的内容。
      • @EmilioGaravaglia 你不是将“内部删除器”与shared_ptr 混淆了吗?在unique_ptr 中,删除器不是类型擦除意义上的“内部”,它是第二个模板参数,默认为std::default_delete&lt;Base&gt;,它只是在拥有的Base 指针上调用delete。所以你确实需要虚拟 dtor。
      猜你喜欢
      • 2015-10-24
      • 2015-05-10
      • 1970-01-01
      • 2013-08-25
      • 1970-01-01
      • 2011-08-04
      • 1970-01-01
      • 1970-01-01
      • 2017-08-13
      相关资源
      最近更新 更多