#c
#c
Вопрос:
Это вопрос из интервью: как мы можем хранить объекты, скажем, 3 разных классов, которые полностью независимы друг от друга.
Мой ответ был таким: создайте массив, в котором хранятся все указатели void. Нравится :
void *array[];
и сохранять указатели на все объекты.элементов массива может быть много.
но я сказал, что для извлечения элементов мы можем использовать динамическое приведение или статическое приведение!
я думаю, это неправильный ответ. я думаю, что dynamic cast
и static cast
предполагается использовать среди зависимых классов.
пожалуйста, поправьте меня, если я ошибаюсь.
если динамическое приведение и статическое приведение не работают.Может быть, мы можем использовать reinterpret cast
.
но правильный ли это способ выполнить эту задачу?
Комментарии:
1. @Rahul Dravid Тебе нужен кортеж.
2. Если вам нужно это сделать, вам следует использовать безопасное решение, подобное
boost::any
.3. @Red Hue: (1) почему (??) и (2) как
4. его не интересовал boost.
5. @Angel: Нет, C не имеет UDT, определенных с помощью ключевого слова
class
. Однако в C вообще есть пользовательские типы (см.:struct
), и поэтому этот вопрос был бы применим к обоим языкам… если бы не{dynamic,static,reinterpret}_cast
ссылки.
Ответ №1:
Почему вы пытаетесь сделать это таким сложным?
struct T {
T1 obj1;
T2 obj2;
T3 obj3;
};
Если вместо этого вы имеете в виду, что у вас есть массив объектов, и каждый элемент может быть любого из трех различных, не связанных типов, то это глупый вопрос для интервью, потому что это глупое занятие.
(Да, вы бы подумали, reinterpret_cast
если бы были вынуждены использовать этот подход из-за ограниченных возможностей трудоустройства и острой необходимости потреблять пищу.)
Комментарии:
1. если это было глупо — зачем были
boost::any
илиboost::variant
созданы?2. Если бы вы пошли по пути без повышения, по крайней мере, сделали бы это различимым объединением? Я знаю, что существуют (строгие) ограничения на то, какие типы могут использоваться в качестве членов объединения, но многие из этих ограничений сняты с появлением c 0x
3. @Nim: Чтобы люди могли обойти глупые проекты. Вы собираетесь утверждать, что само существование вещи означает, что требования, которые приводят к ее использованию, должны быть не глупыми?
4. @sehe, контекст важен, но отвергать что-либо как «глупое» без контекста — это просто глупо, ИМХО. @Tomalak, конечно, нет, я хочу сказать, что само существование подразумевает, что была / есть какая-то ситуация, когда это было / уместно, и делать общее заявление, отвергающее подход, «глупо».
5. @Konstantin: Дочитайте до конца en.wikipedia.org/wiki/Argument_from_silence и en.wikipedia.org/wiki/Argument_from_ignorance
Ответ №2:
Вы могли бы использовать a boost::variant<myfoo, anotherfoo, somefoo> v
для помещения в a vector<v>
, а затем вы можете хранить по одному классу на элемент в векторе, однако он может хранить переменные всех трех типов.
Вы можете найти больше информации о boost::variant здесь
Комментарии:
1. он ожидал ответа, не использующего какую-либо библиотеку, подобную boost.
2. @Rahul, о, хорошо … не знал. Однако это могло бы сработать, IRL
Ответ №3:
dynamic_cast
из void*
не допускается, для этого вам нужен полиморфный указатель (то есть указатель на класс с virtual
методом в нем).
Вы не можете использовать другие приведения, потому что целевой тип приведения неизвестен. Как только вы приводите типизированный указатель на void*
, информация о типе теряется навсегда. Учитывая только указатель, у вас нет шансов получить информацию об этом типе обратно. Вам нужно помнить что-то о типе где-то в какой-то форме. Как насчет enum { one, two, three }
наряду с void*
?
Комментарии:
1.
reinterpret_cast
было бы неплохо.2. @Tomalak
reinterpret_cast<???>
Что ты пишешь внутри скобок? На выбор предлагается три типа.
Ответ №4:
Единственный «правильный» способ сделать это — использовать что-то вроде boost::variant
. Если вы не можете использовать boost, тогда вам придется более менее делать то же самое: реализовать различающее объединение, которое принимает все желаемые типы. Это не так сложно, как может показаться: для типов POD вы можете просто использовать normal union
для данных; для типов, отличных от POD, вы добавляете unsigned char x[sizeof(T)]
к объединению и используете для него размещение new и явное удаление по мере необходимости. И вы добавляете все необходимое к объединению, чтобы обеспечить выравнивание. Таким образом, для пользовательского типа MyClass и double может быть что-то вроде:
class MyVariant
{
public:
enum Type { t_double, t_MyClass };
private:
Type m_type;
union
{
double m_double;
unsigned char m_MyClass[sizeof(MyClass)];
MaxAlignFor<MyClass> m_dummyForAlignment_MyClass;
};
public:
MyVariant( double d )
: m_type( t_double )
{
m_double = d;
}
MyVariant( MyClass constamp; c )
: m_type( t_MyClass )
{
new (m_MyClass) MyClass( c );
}
~MyVariant()
{
switch ( m_type )
{
case t_double:
break;
case t_MyClass:
reinterpret_cast<MyClass*>( m_MyClass )->~MyClass();
break;
}
}
};
И так далее. (Очевидно, что требуется гораздо больше, но это должно дать
базовая платформа.)