c++中的动态对象

Dynamic Object in C++?

本文关键字:对象 动态 c++      更新时间:2023-10-16

我意识到我很可能会得到很多"你不应该这样做,因为……"的答案,他们是最受欢迎的,我可能会完全同意你的推理,但我很好奇这是否可能(正如我想象的那样)。

是否有可能在c++中定义一种动态/通用对象类型,在那里我可以动态地创建存储和检索键/值类型系统的属性?例子:

MyType myObject;
std::string myStr("string1");
myObject.somethingIJustMadeUp = myStr;

注意,显然,somethingIJustMadeUp实际上不是MyType的已定义成员,但它将被动态定义。然后我可以这样写:

if(myObject.somethingIJustMadeUp != NULL);

if(myObject["somethingIJustMadeUp"]);

相信我,我意识到这有多可怕,但我仍然很好奇,是否有可能,是否可以用一种最小化它的可怕的方式。

c++脚本就是你想要的!

的例子:

#include <cppscript>
var script_main(var args)
{
    var x = object();
    x["abc"] = 10;
    writeln(x["abc"]);
    return 0;
}

是一个有效的c++

您可以使用std::map:

做类似的事情:
std::map<std::string, std::string> myObject;
myObject["somethingIJustMadeUp"] = myStr;

现在,如果您想要泛型值类型,那么您可以使用boost::any作为:

std::map<std::string, boost::any> myObject;
myObject["somethingIJustMadeUp"] = myStr;

你也可以检查一个值是否存在:

if(myObject.find ("somethingIJustMadeUp") != myObject.end())
    std::cout << "Exists" << std::endl;

如果你使用boost::any,那么你可以知道实际的值的类型,通过调用.type():

if (myObject.find("Xyz") != myObject.end())
{
  if(myObject["Xyz"].type() == typeid(std::string))
  {
    std::string value = boost::any_cast<std::string>(myObject["Xyz"]);
    std::cout <<"Stored value is string = " << value << std::endl;
  }
}

这还展示了如何使用boost::any_cast来获取存储在boost::any类型对象中的值。

这可以是一个解决方案,使用RTTI多态性

#include <map>
#include <memory>
#include <iostream>
#include <stdexcept>
namespace dynamic
{
    template<class T, class E>
    T& enforce(T& z, const E& e)
    { if(!z) throw e; return z; }
    template<class T, class E>
    const T& enforce(const T& z, const E& e)
    { if(!z) throw e; return z; }
    template<class Derived>
    class interface;
    class aggregate;
    //polymorphic uncopyable unmovable
    class property
    {
    public:
        property() :pagg() {}
        property(const property&) =delete;
        property& operator=(const property&) =delete;
        virtual ~property() {} //just make it polymorphic
        template<class Interface>
        operator Interface*() const
        {
            if(!pagg) return 0;
            return *pagg; //let the aggregate do the magic!
        }
        aggregate* get_aggregate() const { return pagg; }
    private:
        template<class Derived>
        friend class interface;
        friend class aggregate;
        static unsigned gen_id()
        {
            static unsigned x=0;
            return enforce(++x,std::overflow_error("too many ids"));
        }
        template<class T>
        static unsigned id_of()
        { static unsigned z = gen_id(); return z; }
        aggregate* pagg;
    };
    template<class Derived>
    class interface: public property
    {
    public:
        interface() {}
        virtual ~interface() {}
        unsigned id() const { return property::id_of<Derived>(); }
    };

    //sealed movable
    class aggregate
    {
    public:
        aggregate() {}
        aggregate(const aggregate&) = delete;
        aggregate& operator=(const aggregate&) = delete;
        aggregate(aggregate&& s) :m(std::move(s.m)) {}
        aggregate& operator=(aggregate&& s)
        { if(this!=&s) { m.clear(); std::swap(m, s.m); } return *this; }
        template<class Interface>
        aggregate& add_interface(interface<Interface>* pi)
        {
            m[pi->id()] = std::unique_ptr<property>(pi);
            static_cast<property*>(pi)->pagg = this;
            return *this;
        }
        template<class Inteface>
        aggregate& remove_interface()
        { m.erase[property::id_of<Inteface>()]; return *this; }
        void clear() { m.clear(); }
        bool empty() const { return m.empty(); }
        explicit operator bool() const { return empty(); }
        template<class Interface>
        operator Interface*() const
        {
            auto i = m.find(property::id_of<Interface>());
            if(i==m.end()) return nullptr;
            return dynamic_cast<Interface*>(i->second.get());
        }
        template<class Interface>
        friend aggregate& operator<<(aggregate& s, interface<Interface>* pi)
        { return s.add_interface(pi);  }
    private:
        typedef std::map<unsigned, std::unique_ptr<property> > map_t;
        map_t m;
    };
}

/// this is a sample on how it can workout
class interface_A: public dynamic::interface<interface_A>
{
public:
    virtual void methodA1() =0;
    virtual void methodA2() =0;
};
class impl_A1: public interface_A
{
public:
    impl_A1() { std::cout<<"creating impl_A1["<<this<<"]"<<std::endl; }
    virtual ~impl_A1() { std::cout<<"deleting impl_A1["<<this<<"]"<<std::endl; }
    virtual void methodA1() { std::cout<<"interface_A["<<this<<"]::methodA1 on impl_A1 in aggregate "<<get_aggregate()<<std::endl; }
    virtual void methodA2() { std::cout<<"interface_A["<<this<<"]::methodA2 on impl_A1 in aggregate "<<get_aggregate()<<std::endl; }
};
class impl_A2: public interface_A
{
public:
    impl_A2() { std::cout<<"creating impl_A2["<<this<<"]"<<std::endl; }
    virtual ~impl_A2() { std::cout<<"deleting impl_A2["<<this<<"]"<<std::endl; }
    virtual void methodA1() { std::cout<<"interface_A["<<this<<"]::methodA1 on impl_A2 in aggregate "<<get_aggregate()<<std::endl; }
    virtual void methodA2() { std::cout<<"interface_A["<<this<<"]::methodA2 on impl_A2 in aggregate "<<get_aggregate()<<std::endl; }
};
class interface_B: public dynamic::interface<interface_B>
{
public:
    virtual void methodB1() =0;
    virtual void methodB2() =0;
};
class impl_B1: public interface_B
{
public:
    impl_B1() { std::cout<<"creating impl_B1["<<this<<"]"<<std::endl; }
    virtual ~impl_B1() { std::cout<<"deleting impl_B1["<<this<<"]"<<std::endl; }
    virtual void methodB1() { std::cout<<"interface_B["<<this<<"]::methodB1 on impl_B1 in aggregate "<<get_aggregate()<<std::endl; }
    virtual void methodB2() { std::cout<<"interface_B["<<this<<"]::methodB2 on impl_B1 in aggregate "<<get_aggregate()<<std::endl; }
};
class impl_B2: public interface_B
{
public:
    impl_B2() { std::cout<<"creating impl_B2["<<this<<"]"<<std::endl; }
    virtual ~impl_B2() { std::cout<<"deleting impl_B2["<<this<<"]"<<std::endl; }
    virtual void methodB1() { std::cout<<"interface_B["<<this<<"]::methodB1 on impl_B2 in aggregate "<<get_aggregate()<<std::endl; }
    virtual void methodB2() { std::cout<<"interface_B["<<this<<"]::methodB2 on impl_B2 in aggregate "<<get_aggregate()<<std::endl; }
};

int main()
{
    dynamic::aggregate agg1;
    agg1 << new impl_A1 << new impl_B1;
    dynamic::aggregate agg2;
    agg2 << new impl_A2 << new impl_B2;
    interface_A* pa = 0;
    interface_B* pb = 0;
    pa = agg1; if(pa) { pa->methodA1(); pa->methodA2(); }
    pb = *pa;  if(pb) { pb->methodB1(); pb->methodB2(); }
    pa = agg2; if(pa) { pa->methodA1(); pa->methodA2(); }
    pb = *pa;  if(pb) { pb->methodB1(); pb->methodB2(); }
    agg2 = std::move(agg1);
    pa = agg2; if(pa) { pa->methodA1(); pa->methodA2(); }
    pb = *pa;  if(pb) { pb->methodB1(); pb->methodB2(); }
    return 0;
}

是很糟糕。: D

已经做过无数次,不同程度和成功程度。

QT有Qobject,所有与它们相关的东西都是从它派生的。

MFC有一个对象,所有的东西都是从它派生的,就像c++。net一样

我不知道是否有办法让它不那么糟糕,我想如果你像瘟疫一样避免多重继承(这是一个有用的语言特性)并重新实现stdlib会更好。但如果这就是你想要的,那你可能使用了错误的语言。

Java和c#更适合这种编程风格。

#注意,如果我读错了你的问题,请删除这个答案。

查看动态c++