LINUX.ORG.RU

C++, хранение объектов


0

0

Есть два класса: А, В. 

class A
{
public:
	A();
	A(int i);
};


class B
{
public:
	B();
	B(QString s);
};

Смысл такой, что они имеют разный функционал и унаследовать один от другого не желательно.

Необходимо написать класс-хранилище, который хранит три переменные. Причем на месте каждой
переменной может быть и А, и В. Значения передаются статически.


class Storage
{
};

Вызов примерно такой:

A a;
B b;

Storage s(a,b,a);

или так:

Storage s(A(1), B("Hello, world"), A(3));

Как наиболее просто это сделать? Без создания н-го числа конструкторов, переменных и флагов?

Шаблоны?

//undkers

anonymous
()

struct Storage
{
 boost::any value1;
 boost::any value2;
 boost::any value3;

 Storage(const boost::any & v1,
         const boost::any & v2,
         const boost::any & v3):
          value1(v1),value2(v2),value3(v3) {}
};

Только когда обратно вытаскивать будешь, желательно точно знать где 
какой тип. Хотя в случае двух классов можно и перебор устроить.

Vinick ★★
()

можно хранить три tagged union'а, реализованных посредством boost.tuple<A, B> + идентификатор, либо обычного union'а + идентификатор - если, конечно, интерфейс класса Storage позволяет так работать. шаблонные конструкторы никто не запрещал - можно позволить компилятору сгенерировать инстансы самостоятельно, помечая (и раскладывая) значения с помощью boost.typeof. не знаю, что подразумевалось под "наиболее просто" :) возможно, что как раз наоборот - в таком случае есть указанные выше boost.any и boost.variant

jtootf ★★★★★
()

struct A { int a; };
struct B { float b; };

template <class T1, class T2, class T3>
class Storage {
T1 one;
T2 two;
T3 three;

template <class T>
struct TypeId;

template <>
struct TypeId<A> { enum { value = 0 }; };

template <>
struct TypeId<B> { enum { value = 1 }; };

public:
Storage(const T1& a1, const T2& a2, const T3& a3) : one(a1), two(a2), three(a3)
{
}

template <class T>
T& get(int index)
{
    switch (index) {
    case 0:
        assert(TypeId<T>::value == TypeId<T1>::value);
        return reinterpret_cast<T&>(one);
    case 1:
        assert(TypeId<T>::value == TypeId<T2>::value);
        return reinterpret_cast<T&>(two);
    default:
        assert(TypeId<T>::value == TypeId<T3>::value);
        return reinterpret_cast<T&>(three);
    }
}

};

int main()
{
    A a; a.a = 1;
    B b; b.b = 0.1f;

    Storage<A, B, A> s(a, b, a);

    cout << s.get<A>(0).a << endl;
    cout << s.get<B>(1).b << endl;
}

anonymous
()

Можно сделать пустой класс, от него унаследовать эти два. И потом хранить три указателя на базовый класс.

anonymous
()
Ответ на: комментарий от anonymous

>Можно сделать пустой класс, от него унаследовать эти два. И потом хранить три указателя на базовый класс

круто, да. а интерфейс у него какой будет, у этого "пустого класса" ?

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

class Storeable {
protected:
    virtual ~Storeable() = 0;
}

Storeable::~Storeable() {
}

Legioner ★★★★★
()
Ответ на: комментарий от anonymous

> Можно сделать пустой класс, от него унаследовать эти два. И потом хранить три указателя на базовый класс.

Я бы тоже так сделал в данном случае.

smh ★★★
()
Ответ на: комментарий от smh

Лучше хранить умные указатели на базовый класс. ИМХО.

Deleted
()

Афтар хочет объекты хранить. )

anonymous
()
Ответ на: комментарий от jtootf

>>Можно сделать пустой класс, от него унаследовать эти два. И потом хранить три указателя на базовый класс

>круто, да. а интерфейс у него какой будет, у этого "пустого класса" ?

Например, никакого интерфейса у него не будет, а правильный тип будет отыскиваться с помощью dynamic_cast.

Эти классы с хорошей вероятностью что-то объединяет (не зря же, в конце концов, их хотят упихивать вместе), так что топикстартер может продолжить задавать вопросы и искать более изящный дизайн ;)

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.