在某个地方,我觉得需要通过类似INI的接口通过单个类更清楚地管理不同的类,所以我写了
#include <vector>
#include <string>
#include <memory>
#include <iostream>
struct A {
using getter = int(A::*)();
using setter = void(A::*)(int);
virtual std::string get_name() = 0;
virtual getter get_getter(std::string property_name) = 0;
};
struct PropertyManager {
template<class Type>
using pointer = std::shared_ptr<Type>;
using string_type = std::string;
int get_property(string_type object_name,string_type property_name) {
A::getter property_getter = nullptr;
pointer<A> mo;
for(auto& o : objects) {
if (o->get_name() == object_name) {
mo = o;
property_getter = o->get_getter(property_name);
break;
}
}
if (property_getter == nullptr)
std::runtime_error{std::string{"no object named \""} + object_name + "\" found"};
return (mo.get()->*property_getter)();
}
void add_a(pointer<A> new_A) {
objects.push_back(new_A);
}
private:
std::vector<pointer<A>> objects;
};
struct testClass : A {
int my_number() {
return 8;
}
std::string get_name() override {
return "testClass";
}
getter get_getter(std::string property_name) override {
if (property_name == "my_number")
return static_cast<A::getter>(my_number);
throw std::runtime_error{std::string{"no property \""} + property_name + "\" found"};
}
};
int main() {
PropertyManager p;
p.add_a(std::make_shared<testClass>());
std::cout << p.get_property("testClass","my_number");
}
但是作为“属性”可以有任何其他类型,所以我觉得需要对代码进行模板化,但是由于不能对虚拟函数进行模板化,所以我不能,因此我显然无法通过此接口来实现,还有其他方法可以做到这一点吗,我的意思是说,有一个可以通过类似接口管理不同类的不同属性的类
我仅限于c ++ 11
答案 0 :(得分:0)
好吧,我的命名方案有点笨,可以为您找到更好的东西,但是您可以尝试以下方法:
// initial base class we can return from A without having to worry about templates
class Getter
{
public:
virtual ~Getter() { }
};
// intermediate class intended to be dynamic_casted to, see below
template<typename R>
class TheGetter : public Getter
{
public:
virtual R operator()() = 0;
};
// final implementation
template<typename T, typename R>
class TheTheGetter : public TheGetter<R>
{
T* t;
R (T::*getter)();
public:
TheTheGetter(T* t, R (T::*getter)())
: t(t), getter(getter)
{ }
R operator()() override
{
return (t->*getter)();
}
};
struct A
{
virtual ~A() { };
virtual std::string get_name() = 0;
// as virtual, cannot be a template, thus Getter cannot be either...
virtual Getter& get_getter(std::string name) = 0;
};
// let's make a template function of:
template<typename T>
T PropertyManager::get_property(string_type object_name, string_type property_name)
{
for(auto& o : objects)
{
if (o->get_name() == object_name)
{
auto& getter = o->get_getter(property_name);
// now with the intermediate class, we do not have to care for
// o's true type...
auto* theGetter = dynamic_cast<TheGetter<T>*>(&getter);
if(theGetter)
{
return (*theGetter)();
}
throw std::runtime_error("... is of bad type ...");
}
}
throw std::runtime_error("...");
}
class Test : public A
{
public:
Test()
: gInt(this, &Test::getInt),
gDouble(this, &Test::getDouble)
{ }
int getInt() { return 7; }
double getDouble() { return 10.12; }
std::string get_name() override
{
return "Test";
}
Getter& get_getter(std::string name) override
{
if(name == "int")
{
return gInt;
}
if(name == "double")
{
return gDouble;
}
throw std::runtime_error("...");
}
private:
TheTheGetter<Test, int> gInt;
TheTheGetter<Test, double> gDouble;
};
int main(int argc, char* argv[])
{
PropertyManager p;
p.add_a(std::make_shared<Test>());
auto vi = p.get_property<int>("Test", "int");
auto vd = p.get_property<double>("Test", "double");
std::cout << vi << ' ' << vd << std::endl;
return 0;
}