加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

C – 通过单个指针访问多个对象的接口

发布时间:2020-12-16 07:09:23 所属栏目:百科 来源:网络整理
导读:我需要存储一个指向对象的指针容器. 这些对象有一些常见的方法/属性(接口),我想强制执行(可能在编译时)和使用. 例: struct A{ void fly(){}};struct B{ void fly(){}};A a;B b;std::vectorsome * objects;objects.push_back(a);objects.push_back(b);for(au
我需要存储一个指向对象的指针容器.
这些对象有一些常见的方法/属性(接口),我想强制执行(可能在编译时)和使用.
例:

struct A{
    void fly(){}
};

struct B{
    void fly(){}
};

A a;
B b;
std::vector<some *> objects;
objects.push_back(&a);
objects.push_back(&b);

for(auto & el: objects)
    el->fly();

更简单的解决方案是A和B继承一个像FlyingClass这样的公共基类:

struct FlyingClass{
    void fly(){}
};
struct A: public FlyingClass { ...
struct B: public FlyingClass { ...

并创建一个

std::vector<FlyingClass *> objects;

这将起作用并且还强制执行这样的事实:我只能添加可以飞行的对象(实现FlyingClass).

但是如果我需要实现一些其他常见的方法/属性而不将它们与上面的基类耦合呢?

例:

struct A{
    void fly(){}
    void swim(){}
};

struct B{
    void fly(){}
    void swim(){}
};

我想这样做:

for(auto & el: objects) {
    el->fly();
    ...
    el->swim();
    ...
}

更一般地,我将能够调用一个函数传递其中一个指针并访问常见的方法/属性,如:

void dostuff(Element * el){
    el->fly();
    el->swim();
}

我可以尝试从另一个接口继承,如:

struct SwimmingClass{
    void swim(){}
};

struct A: public FlyingClass,public SwimmingClass { ...
struct B: public FlyingClass,public SwimmingClass { ...

但那么容器应该包含什么?

std::vector<FlyingClass&&SwimmingClass *> objects;

当然,我可以实现SwimmingFlyingClass,但如果我需要RunningClass等,那将会是一场噩梦.
换句话说,如何在不耦合它们的情况下实现指向多个接口的指针?

或者有一些重新思考问题的模板方法?
如果有一种优雅且可维护的方式,即使运行时类型信息也可以在我的应用程序中接受.

解决方法

有可能以一种漂亮的TMP方式执行此操作,这在运行时有点贵.重新设计是有利的,因此不需要这样做.长期和短期是,如果没有C语言提供的语言支持,您想要做的事情是不可能的.

至于丑陋,请保护你的眼睛:

struct AnyBase { virtual ~AnyBase() {} }; // All derived classes inherit from.
template<typename... T> class Limited {
    AnyBase* object;
    template<typename U> Limited(U* p) {
        static_assert(all<is_base_of<T,U>...>::value,"Must derive from all of the interfaces.");
        object = p;
    }        
    template<typename U> U* get() {
        static_assert(any<is_same<U,T>...>::value,"U must be one of the interfaces.");
        return dynamic_cast<U*>(object);
    }
}

其中一些东西没有被定义为标准,所以我将完成它.构造函数上的static_assert强制U从T的所有T继承.我可能有U和T错误的方式,并且all的定义留给读者.

getter只需要U是模板参数T之一….然后我们事先知道dynamic_cast会成功,因为我们静态地检查了约束.

这很难看,但应该有用.考虑一下

std::vector<Limited<Flying,Swimming>> objects;
for(auto&& obj : objects) {
    obj.get<Flying>()->fly();
    obj.get<Swimming>()->swim();
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读