【问题标题】:templatizing a virtual function, managing different classes property from single class模板化一个虚函数,管理来自单个类的不同类属性
【发布时间】:2018-12-07 16:27:09
【问题描述】:

在某个地方,我觉得需要通过类似 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

【问题讨论】:

  • 你不应该包含来自bits目录的头文件!
  • 我只需要那个来测试
  • 从 A 派生的类集是有限的还是可能是无限的?
  • 如果无限会好很多
  • std::function&lt;std::any(const A&amp;)&gt;...

标签: c++ oop templates interface template-meta-programming


【解决方案1】:

好的,我的命名方案有点笨,让你找到更好的东西,但你可以试试这个:

// 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;
}

【讨论】:

    猜你喜欢
    • 2022-12-19
    • 2019-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-11
    • 2012-04-20
    • 1970-01-01
    相关资源
    最近更新 更多