我想创建一个表现某种方式的类-例如根据传递给其构造函数的“类型”,从函数double getValue(const int& x) const
中吐出某些值。现在我有两种方法:
switch
时评估getValue
语句,以决定使用哪种实现。switch
语句创建一个表示所需实现的内部对象。因此,switch
本身不再需要getValue
。方法1“似乎”效率低下,因为每次我调用switch
时都会调用getValue
。方法2似乎有些笨拙,因为我需要利用<memory>
,这也使复制/分配我的类变得很简单。
还有其他更清洁的方法来解决这样的问题吗?
代码示例:
#include <memory>
enum class ImplType { Simple1, Simple2 /* more cases */ };
class MyClass1
{
private:
const ImplType implType;
public:
MyClass1(const ImplType& implType) : implType(implType) { }
double getValue(const int& x) const
{
switch (implType)
{
case ImplType::Simple1: return 1; /* some implemention */
case ImplType::Simple2: return 2; /* some implemention */
}
}
};
class MyClass2
{
private:
struct Impl { virtual double getValue(const int& x) const = 0; };
struct ImplSimple1 : Impl { double getValue(const int& x) const override { return 1; /* some implemention */ } };
struct ImplSimple2 : Impl { double getValue(const int& x) const override { return 2; /* some implemention */ } };
const std::unique_ptr<Impl> impl;
public:
MyClass2(const ImplType& implType) : impl(std::move(createImplPtr(implType))) { }
static std::unique_ptr<Impl> createImplPtr(const ImplType& implType)
{
switch (implType)
{
case ImplType::Simple1: return std::make_unique<ImplSimple1>();
case ImplType::Simple2: return std::make_unique<ImplSimple2>();
}
}
double getValue(const int& x) const { return impl->getValue(x); }
};
int main()
{
MyClass1 my1(ImplType::Simple1);
MyClass2 my2(ImplType::Simple1);
return 0;
}
答案 0 :(得分:1)
您的代码基本上是在模仿虚拟方法(粗俗地说:相同的接口,但是在运行时选择了实现),因此,如果您确实使用虚拟方法,则代码可以更加简洁:
#include <memory>
struct base {
virtual double getValue(const int& x) const = 0;
};
struct impl1 : base {
double getValue(const int& x) { return 1.0; }
};
struct impl2 : base {
double getValue(const int& x) { return 2.0; }
};
// ... maybe more...
enum select { impl1s, impl2s };
base* make_impl( select s) {
if (s == impl1s) return new impl1();
if (s == impl2s) return new impl2();
}
int main() {
std::shared_ptr<base> x{ make_impl(impl1) };
}
不确定这是否是您想要的。顺便说一句,使用<memory>
不应让您感到“笨拙”,而应该为我们在c ++中拥有如此出色的工具而感到自豪;)。
编辑:如果您不希望用户使用(智能)指针,则将以上内容包装在另一个类中:
struct foo {
shared_ptr<base> impl;
foo( select s) : impl( make_impl(s) ) {}
double getValue(const int& x) { return impl.getValue(x); }
};
现在用户可以做
int main() {
auto f1 { impl1s };
auto f2 { impl2s };
f1.getValue(1);
f2.getValue(2);
}
答案 1 :(得分:1)
如果您可以选择一组封闭的类型,则需要std::variant
:
using MyClass = std::variant<MyClass1, MyClass2, MyClass3, /* ... */>;
它不使用动态分配-基本上是union
的类型安全的现代替代方案。
答案 2 :(得分:0)
更多面向对象的方法:
class Interface
{
public:
virtual int getValue() = 0;
};
class GetValueImplementation1 : public Interface
{
public:
int getValue() {return 1;}
};
class GetValueImplementation2 : public Interface
{
public:
int getValue() {return 2;}
};
class GeneralClass
{
public:
GeneralClass(Interface *interface) : interface(interface) {}
~GeneralClass()
{
if (interface)
delete interface;
}
int getValue() { return interface->getValue(); }
private:
Interface *interface;
};
因此,在这种情况下,您可以使用它而无需任何指针:
int main()
{
GeneralClass obj1(new GetValueImplementation1());
GeneralClass obj2(new GetValueImplementation2());
cout << obj1.getValue() << " " << obj2.getValue();
return 0;
}
输出将是:
1 2
但是在这种情况下,您应该小心使用空指针或在GeneralClass
内使用智能指针。