2015-03-16 3 views
0

РассмотримАдресности типа с использованием ключевого слова в производных классах

struct AbstractClass {}; 

struct Derived1 : AbstractClass { 
    using type = int; 
}; 

struct Derived2 : AbstractClass { 
    using type = char; 
}; 

struct Derived3 : AbstractClass { 
    using type = bool; 
}; 

int main() { 
    AbstractClass* a[] = {new Derived1, new Derived2, new Derived3}; 
} 

Как получить type от а [0], а [1], а [2]?

Вот что я пытаюсь выполнить. Наверное, нет другого способа сделать это, чем это?

#include <iostream> 

struct Object { virtual ~Object() = default; }; 
struct A : Object {}; 
struct B : Object {}; 
struct C : Object {}; 

struct AbstractClass { 
    virtual void take (Object*) { 
     std::cout << "Accepted.\n"; 
    } 
}; 

template <typename...> struct ObjectTypes; 

template <typename First, typename... Rest> 
struct ObjectTypes<First, Rest...> : ObjectTypes<Rest...> { 
    bool operator()(Object* o) const { 
     if (dynamic_cast<First*>(o)) 
      return true; 
     return ObjectTypes<Rest...>::operator()(o); 
    } 
}; 

template <> 
struct ObjectTypes<> { 
    bool operator()(Object*) const {return false;} 
}; 

struct Derived1 : AbstractClass { 
    using type = ObjectTypes<A,B>; 
    virtual void take (Object* o) override { 
     if (type()(o)) // This is why I want to use type from AbstractClass. 
      return AbstractClass::take(o); 
     std::cout << "Rejected.\n"; 
    } 
}; 

struct Derived2 : AbstractClass { 
    using type = ObjectTypes<A,C>; 
    virtual void take (Object* o) override { 
     if (type()(o)) 
      return AbstractClass::take(o); 
     std::cout << "Rejected.\n"; 
    } 
}; 

struct Derived3 : AbstractClass { 
    using type = ObjectTypes<B,C>; 
    virtual void take (Object* o) override { 
     if (type()(o)) 
      return AbstractClass::take(o); 
     std::cout << "Rejected.\n"; 
    } 
}; 

int main() { 
    AbstractClass* abs[] = {new Derived1, new Derived2, new Derived3}; 
    A* a = new A; 
    B* b = new B; 
    C* c = new C; 
    for (AbstractClass* x : abs) { 
     x->take(a); 
     x->take(b); 
     x->take(c); 
     std::cout << "------------\n"; 
    } 
} 

Обратите внимание на повторения в Derived1, Derived2, Derived3 и т. Д.?? Поэтому моя первоначальная цель состояла в том, чтобы все это было сделано в базовом классе AbstractClass.

+6

Вы не можете. Типы должны быть известны во время компиляции. Если вы объясните, что вы на самом деле пытаетесь сделать, мы сможем помочь вам найти решение. – Brian

+0

@Brian. Предположим, что у меня есть 'AbstractClass * a'. Поскольку AbstractCass является абстрактным, '' a' имеет 'type', и мне нужно его использовать. – prestokeys

+0

Нет, я имею в виду более широко, для чего это будет использоваться? – Brian

ответ

1

Я скорее думал о том, как СТГ:

#include <iostream> 

struct Object { virtual ~Object() = default; }; 
struct A : Object {}; 
struct B : Object {}; 
struct C : Object {}; 

struct SuperObjectType { 
public: 
    virtual bool operator()(Object *o) const = 0; 
}; 

template <typename First, typename... Rest> 
struct ObjectTypes: SuperObjectType { 
    bool operator()(Object* o) const override { 
     if (dynamic_cast<First*>(o)) 
      return true; 
     return ObjectTypes<Rest...>()(o); 
    } 
}; 

template <typename OnlyOne> 
struct ObjectTypes<OnlyOne>: SuperObjectType { 
    bool operator()(Object* o) const override { 
     return dynamic_cast<OnlyOne*>(o); 
    } 
}; 

struct AbstractClass { 
    SuperObjectType *sot; 
    void take (Object* o) { 
     if ((*sot)(o)) { 
      std::cout << "ACCEPTED" << std::endl; 
     } else { 
      std::cout << "REJECTED" << std::endl; 
     } 
    } 
}; 
struct Derived1 : AbstractClass { 
    Derived1() { 
     sot = new ObjectTypes<A,B>; 
    } 
}; 

struct Derived2 : AbstractClass { 
    Derived2() { 
     sot = new ObjectTypes<A,C>; 
    } 
}; 

struct Derived3 : AbstractClass { 
    Derived3() { 
     sot = new ObjectTypes<B,C>; 
    } 
}; 

int main() { 
    AbstractClass* abs[] = {new Derived1, new Derived2, new Derived3}; 
    A* a = new A; 
    B* b = new B; 
    C* c = new C; 
    for (AbstractClass* x : abs) { 
     x->take(a); 
     x->take(b); 
     x->take(c); 
     std::cout << "------------\n"; 
    } 
} 

Но я рад, что я вдохновило вас;)

Minor альтернатива (возможно) ускорить работу:

template <typename First, typename... Rest> 
struct ObjectTypes: ObjectTypes<Rest...> { // Derive from ObjectTypes<Rest...> instead. 
    virtual bool operator()(Object* o) const override { 
     if (dynamic_cast<First*>(o)) 
      return true; 
     return ObjectTypes<Rest...>::operator()(o); 
     // So now ObjectTypes<Rest...>::operator() can be used, and thus avoid instantiation. 
    } 
}; 

template <typename T> 
struct ObjectTypes<T>: SuperObjectType { 
    virtual bool operator()(Object* o) const override { 
     return dynamic_cast<T*>(o); 
    } 
}; 

Поскольку ObjectTypes<T> является производным от SuperObjectType для любого типа Т, то ObjectTypes<First, Rest...> происходит от SuperObjectType, а также (будучи производным от ObjectTypes<Last>, были Последнее является последним типом в покое ...). Так что все еще работает (проверено).

+0

Это прекрасное решение. Я никогда не думал о гомогеонизации «ObjectTypes » с родителем для создания поля для AbstractClass. Было бы интересно проверить оба решения, чтобы увидеть, какой из них выполняется быстрее. Хотя я думаю, что оба будут одинаковыми. – prestokeys

+0

Спасибо за оценку. На самом деле это первое, что пришло мне в голову, чтобы решить вашу проблему. Я думаю, хотя ваше решение одинаково хорошо. –

+0

Я оценил, что ваша работа выполняется быстрее из-за отсутствия поиска в v-таблице и без динамического каста (при небольшой стоимости 4 байта памяти). Изменить: оба решения имеют одинаковый размер байта для AbstractClass, потому что у меня есть виртуальная функция, поэтому ваша побеждает. – prestokeys

1

Решение, вдохновленное предложением Войцеха Фромберга, хотя я не уверен, что это то, что он имел в виду. Я действительно не знаю, что он имел в виду, и я думаю, что он имел в виду что-то еще, и хотел бы увидеть его решение и узнать, что он на самом деле говорил.

#include <iostream> 

struct Object { virtual ~Object() = default; }; 
struct A : Object {}; 
struct B : Object {}; 
struct C : Object {}; 

template <typename...> struct ObjectTypes; 

template <typename First, typename... Rest> 
struct ObjectTypes<First, Rest...> : ObjectTypes<Rest...> { 
    bool operator()(Object* o) const { 
     if (dynamic_cast<First*>(o)) 
      return true; 
     return ObjectTypes<Rest...>::operator()(o); 
    } 
}; 

template <> 
struct ObjectTypes<> { 
    bool operator()(Object*) const {return false;} 
}; 

struct AbstractClass { 
    virtual void take (Object*) = 0; 
    template <typename... Ts> void takeHelper (Object* o, ObjectTypes<Ts...>&& types) { 
     if (types(o)) std::cout << "Accepted.\n"; // And now do whatever with o. 
     else std::cout << "Rejected.\n"; 
    } 
}; 

template <typename Derived> 
struct AbstractClassCRTP : AbstractClass { 
    virtual void take (Object* o) override { 
     takeHelper(o, typename Derived::type{}); 
    } 
}; 

struct Derived1 : AbstractClassCRTP<Derived1> { 
    using type = ObjectTypes<A,B>; 
}; 

struct Derived2 : AbstractClassCRTP<Derived2> { 
    using type = ObjectTypes<A,C>; 
}; 

struct Derived3 : AbstractClassCRTP<Derived3> { 
    using type = ObjectTypes<B,C>; 
}; 

int main() { 
    AbstractClass* abs[] = {new Derived1, new Derived2, new Derived3}; 
    A* a = new A; 
    B* b = new B; 
    C* c = new C; 
    for (AbstractClass* x : abs) { 
     x->take(a); 
     x->take(b); 
     x->take(c); 
     std::cout << "------------\n"; 
    } 
} 

Выход:

Accepted. 
Accepted. 
Rejected. 
------------ 
Accepted. 
Rejected. 
Accepted. 
------------ 
Rejected. 
Accepted. 
Accepted. 
Смежные вопросы