【问题标题】:Enforce static method overloading in child class in C++在 C++ 中的子类中强制静态方法重载
【发布时间】:2010-10-31 18:23:02
【问题描述】:

我有这样的事情:

class Base
{
  public:
    static int Lolz()
    {
      return 0;
    }
};

class Child : public Base
{
  public:
    int nothing;
};

template <typename T>
int Produce()
{
  return T::Lolz();
}

Produce<Base>();
Produce<Child>();

两者都返回 0,这当然是正确的,但不需要。无论如何要在第二个类中强制执行 Lolz() 方法的显式声明,或者在使用 Produce&lt;Child&gt;() 时可能会引发编译时错误?

或者是糟糕的 OO 设计,我应该做一些完全不同的事情?

编辑:

我基本上想做的是做这样的事情:

Manager manager;

manager.RegisterProducer(&Woot::Produce, "Woot");
manager.RegisterProducer(&Goop::Produce, "Goop");

Object obj = manager.Produce("Woot");

或者,更一般地说,一个外部抽象工厂,它不知道它正在生产的对象的类型,因此可以添加新类型而无需编写更多代码。

【问题讨论】:

  • 您能提供有关上下文的详细信息吗?看起来你的编程有点像工厂的东西。
  • 如果您的 Manager 的 Produce 方法无论如何都返回一个指向基类的指针,那么使用模板有什么意义呢?你可以像这样定义你的 RegisterProducer 方法: void RegisterProducer(Object * (*pfnProduce)(), const char * pName)

标签: c++ class templates oop static


【解决方案1】:

有两种方法可以避免它。其实,这取决于你想说什么。

(1) 将Produce()作为Base类的接口。

template <typename T>
int Produce()
{
  return T::Lolz();
}
class Base
{
    friend int Produce<Base>();

protected:
    static int Lolz()
    {
        return 0;
    }
};

class Child : public Base
{
public:
    int nothing;
};

int main(void)
{
    Produce<Base>(); // Ok.
    Produce<Child>(); // error :'Base::Lolz' : cannot access protected member declared in class 'Base'
}

(2) 使用模板特化。

template <typename T>
int Produce()
{
  return T::Lolz();
}
class Base
{
public:
    static int Lolz()
    {
        return 0;
    }
};

class Child : public Base
{
public:
    int nothing;
};

template<>
int Produce<Child>()
{
    throw std::bad_exception("oops!");
    return 0;
}

int main(void)
{
    Produce<Base>(); // Ok.
    Produce<Child>(); // it will throw an exception!
}

【讨论】:

  • 谢谢! 1 号正是我想要的。
【解决方案2】:

没有办法覆盖子类中的静态方法,只能隐藏它。也没有任何类似于抽象方法的东西会强制子类提供定义。如果你真的需要在不同的子类中有不同的行为,那么你应该让 Lolz() 成为一个实例方法并照常覆盖它。

我怀疑您正在接近这里的设计问题。面向对象设计的原则之一是替代原则。它基本上说如果 B 是 A 的子类,那么在可以使用 A 的任何地方使用 B 都必须是有效的。

【讨论】:

    【解决方案3】:

    C++ 不支持虚拟静态函数。想想 vtable 必须是什么样子才能支持它,你会意识到这是不行的。

    【讨论】:

      【解决方案4】:

      或者在使用 Produce() 时可能会引发编译时错误

      对此的现代解决方案是使用delete

      class Child : public Base
      {
        public:
          int nothing;
          static int Lolz() = delete;
      };
      

      它有助于避免大量样板并清楚地表达您的意图。

      【讨论】:

        【解决方案5】:

        据我了解您的问题,您想禁用父类的静态方法。你可以在派生类中做这样的事情:

        
        class Child : public Base
        {
        public:
            int nothing;
        private:
            using Base::Lolz;
        };
        

        现在Child::Lolz 变为私有。 但是,当然,修复设计要好得多:)

        【讨论】:

          猜你喜欢
          • 2021-01-25
          • 1970-01-01
          • 1970-01-01
          • 2013-08-02
          • 2010-12-26
          • 1970-01-01
          • 1970-01-01
          • 2019-07-09
          • 2015-06-09
          相关资源
          最近更新 更多