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
。与Peter
和Steve
相同。他们的工作有一些独特之处。我可能会产生数百个man
实例,并且需要为每个实例重新定义do_something()
函数。
我不喜欢两次尝试:
1)Joe
作为单例类,它继承自man。
2)将函数指针传递给do_something()
。
我想为do_something()
的每个实例重新定义man
函数。有可能吗?
答案 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";}