为每个实例重新定义方法

时间:2018-07-17 11:53:18

标签: c++ oop

class man {
  public:
    void do_something();
}

int main(){
  man Joe, Peter, Steve;
  Joe.do_something();
  Peter.do_something();
  Steve.do_something();

  return 0;
}

只有一个唯一的man被称为Joe。与PeterSteve相同。他们的工作有一些独特之处。我可能会产生数百个man实例,并且需要为每个实例重新定义do_something()函数。

我不喜欢两次尝试: 1)Joe作为单例类,它继承自man。 2)将函数指针传递给do_something()

我想为do_something()的每个实例重新定义man函数。有可能吗?

4 个答案:

答案 0 :(得分:4)

最简单的方法是将操作作为参数传递给构造函数。

您可以使用std::function或lambda。 或创建另一个“动作”类。

class Action
{
public:
    virtual ~Action();
    virtual void something() = 0;
};

如果从中继承想要的细节,那么每个man都可以使用do_something方法中的操作。

答案 1 :(得分:2)

一种简单的方法是使用std::function自定义行为:

#include <iostream>
#include <functional>

class man {
  public:
    std::function<void()> something;
    void do_something() { something(); }
}

int main(){
  man Joe, Peter, Steve;
  Joe.something = [] () { std::cout << "Joe something."; };
  Joe.do_something();
  Peter.something = [] () { std::cout << "Peter something."; };
  Peter.do_something();
  Steve.something = [] () { std::cout << "Steve something."; };
  Steve.do_something();

  return 0;
}

如果您需要更多功能,建议您将一个抽象类添加到man类中,该类需要重写do_something()。然后为每个不同的操作从该类继承。

答案 2 :(得分:1)

是的。看一下策略设计模式: https://en.wikipedia.org/wiki/Strategy_pattern

#include <memory>
#include <string>
#include <iostream>

class man {
public:
  man (std::string const& name) : name_(name) {}
  virtual void do_something() {
    std::cout << name_ << " does it" << std::endl;
  };
protected:
  std::string name_;
};

class Joe : public man{
public:
  Joe() : man("Joe") {}
};

class Fred : public man {
public:
  Fred() : man("Fred") {}
  virtual void do_something() override final {
    man::do_something();
    std::cout << "  ... but Fred can do way more" << std::endl;
  }
};

class ConcreteMan {
public:

  ConcreteMan(std::string const& name) : man_(nullptr) {
    if (name == "Joe")
      man_.reset(new Joe());
    else if (name == "Fred")
      man_.reset(new Fred());
    else
      std::cerr << "No such man " << name << std::endl;
  }
  void do_something() {
    if (man_ != nullptr) 
      man_->do_something();
    else 
      std::cerr << "No real man" << std::endl;
  }
private:
  std::unique_ptr<man> man_;
};

int main() {
  ConcreteMan joe("Joe"), fred("Fred"), donald("Donald");
  joe.do_something();
  fred.do_something();
  donald.do_something();
  return 0;
}

答案 3 :(得分:0)

解决方案1:标签分发

您只需添加一个类型并编写行为即可。

struct Joe{ void do(){std::cout << "drink";} };
struct Peter{ void do(){std::cout << "smoke";} };
struct Steve{ void do(){std::cout << "sleep";} };

class man {
  public:
   template<typename T>
   void do_something(){ T.do();}
}

由于每次都必须调用do_something(),因此可以考虑将结构保存在man类中,因此可以删除模板:

struct man_detail{}
struct Joe : public man_detail{ void do(){std::cout << "drink";} };
struct Peter : public man_detail{ void do(){std::cout << "smoke";} };
struct Steve : public man_detail{ void do(){std::cout << "sleep";} };

class man{
public:
   man(man_detail md) : maninfo(md){}

   void do_something() { maninfo.do(); }

private:
   man_detail maninfo;
};

您的man_detail可以随时扩展为接口并添加更多方法。

解决方案2:模板专业化

您的man类成为模板,因此man和man是完全不同的类型,您只能提供部分专业化。

struct Joe{};
struct Peter{};
struct Steve{};

template <typename T>
class man
{
   void do_something() {}
}

template <Joe> void man::do_something(){std::cout << "drink";}
template <Peter> void man::do_something(){std::cout << "smoke";}
template <> void man::do_something(){std::cout << "sleep";}