Добрый!
Вопрос нуба. В проге решил из структуры сделать объекты, что бы всё было как у взрослых дядек. Но ничего не получилось. Вот упрощенный вариант:
class A
{
public:
virtual void VFunc() = 0;
};
class B: public A
{
public:
void VFunc()
{
printf("class B\n");
}
};
class C: public A
{
public:
void VFunc()
{
printf("class C\n");
}
};
// здесь можно что-то упростить?
B b = B();
C c = C();
static A *a[] = {&b, &c, 0 /*маркер конца списка*/};
static A *aa[] = {&B(), &C(), 0 /*маркер конца списка*/};
static A aaa[] = {B(), C()};
int _tmain(int argc, _TCHAR* argv[])
{
// пока работает
a[0]->VFunc();
a[1]->VFunc();
// коварно вылетает
aa[0]->VFunc();
aa[1]->VFunc();
// даже не линкуется
// в реальной проге линкуется, но идет вызов pure virtual
aaa[0].VFunc();
aaa[1].VFunc();
return 0;
}
Здравствуйте, CoolCmd, Вы писали:
CC>Добрый! CC>Вопрос нуба. В проге решил из структуры сделать объекты, что бы всё было как у взрослых дядек. Но ничего не получилось. Вот упрощенный вариант: CC>
class A
CC>// здесь можно что-то упростить?
CC>B b = B();
CC>C c = C();
CC>static A *a[] = {&b, &c, 0 /*маркер конца списка*/};
CC>static A *aa[] = {&B(), &C(), 0 /*ошибка -- в массив попадет указатель на временный объект*/};
CC>static A aaa[] = {B(), C()} //ошибка -- в массив объктов типа А нельзя помещать В и С;
Здравствуйте, CoolCmd, Вы писали:
CC>... ничего не получилось. Вот упрощенный вариант: CC>
class A
CC>{
CC>public:
CC> virtual void VFunc() = 0;
CC>};
CC>// здесь можно что-то упростить?
CC>B b = B();
CC>C c = C();
B b;
C c;
CC>static A *aa[] = {&B(), &C(), 0 /*маркер конца списка*/};
Должна быть ошибка компиляции: 'B()' и 'C()' — rvalue, оператор '&' требует lvalue. MSVC должен детектировать эту ошибку с /Za
CC>static A aaa[] = {B(), C()};
Должна быть ошибка компиляции: Класс 'A' является абстрактным. Массив объектов такого класса создать нельзя.
Во-первых, избавляемся от необходимости каким-то особым способом отмечать конец массива. У вектора есть size().
Во-вторых, не морочим себе голову временем жизни объектов — тогда как, храня голые указатели на внешние объекты, пришлось бы следить за ними всеми.
Особенно, если эти объекты находятся на стеке...
Что же касается исходного кода,
B b; C c;
A* arr1[] = { &b, &c, 0 }; // объекты отдельно, указатели отдельно, всё правильно
A* arr2[] = { &B(), &C(), 0 }; // указатели на временные объекты (которые были разрушены сразу после создания массива)
A arr3[] = { B(), C() }; // срезка объектов типа B и C до типа A (копирование)
это не должно компилироваться, но — в первом случае мы нарываемся на расширение языка (MSVC), а во втором — на баг компилятора, позволяющий создать экземпляры абстрактного класса.
Естественно, что во втором массиве просто невалидные указатели, а в третьем — объекты с абстрактными методами. Ни те, ни другие не пригодны к использованию.
Перекуём баги на фичи!
Re[2]: Вызов нескольких derived classes из массива
Здравствуйте, Юрий Жмеренецкий, Вы писали:
CC>>static A *aa[] = {&B(), &C(), 0 /*маркер конца списка*/}; ЮЖ>Должна быть ошибка компиляции: 'B()' и 'C()' — rvalue, оператор '&' требует lvalue. MSVC должен детектировать эту ошибку с /Za
Понятно, я расширения не отключаю, полезная штука.
А если везде везде везде поставить const, все равно будет ошибка?
CC>>static A aaa[] = {B(), C()}; ЮЖ>Должна быть ошибка компиляции: Класс 'A' является абстрактным. Массив объектов такого класса создать нельзя.
vs2008sp1. Молчит проклятый.
Здравствуйте, Кодт, Вы писали:
К>Я бы сделал так К>
Здравствуйте, CoolCmd, Вы писали:
CC>Еще один вопрос. Часто вижу, что когда нужно передать объект в функцию, то вместо A *a делают A& a. Почему?
Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней.
Дык это понятно. Почему предпочтительней?
Здравствуйте, CoolCmd, Вы писали:
CC>Здравствуйте, LaptevVV, Вы писали:
LVV>>Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней. CC>Дык это понятно. Почему предпочтительней?
Потому что ссылка инициализируется один раз, и потом не менеятся, указатель же может указывать на различные объекты в течении жизни, или может не указывать вообще ни на что(неинициализирован), поэтому при передаче параметров через указатели приходится проверять их на ноль, но и это не избавит от возможных ошибок, так как указатель может указывать на "мусор". Ссылки лишины этих недостатков.
Здравствуйте, v2kochetov, Вы писали:
V>Здравствуйте, CoolCmd, Вы писали:
CC>>Здравствуйте, LaptevVV, Вы писали:
LVV>>>Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней. CC>>Дык это понятно. Почему предпочтительней? V>Потому что ссылка инициализируется один раз, и потом не менеятся, указатель же может указывать на различные объекты в течении жизни, или может не указывать вообще ни на что(неинициализирован), поэтому при передаче параметров через указатели приходится проверять их на ноль, но и это не избавит от возможных ошибок, так как указатель может указывать на "мусор". Ссылки лишины этих недостатков.
Ссылка прежде всего плоха тем, что не даёт ясности относительно вопроса кто владеет объектом и должен его удалять.
Здравствуйте, skeptik_, Вы писали:
LVV>>>>Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней. CC>>>Дык это понятно. Почему предпочтительней? V>>Потому что ссылка инициализируется один раз, и потом не менеятся, указатель же может указывать на различные объекты в течении жизни, или может не указывать вообще ни на что(неинициализирован), поэтому при передаче параметров через указатели приходится проверять их на ноль, но и это не избавит от возможных ошибок, так как указатель может указывать на "мусор". Ссылки лишины этих недостатков.
_>Ссылка прежде всего плоха тем, что не даёт ясности относительно вопроса кто владеет объектом и должен его удалять.
Как это не дает? как раз передача по ссылке говорит о том, что объектом владеет вызывающая функция. Передача по ссылке никогда не предполагает удаление объекта.
Что-то вы про ссылке не все понимаете.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Здравствуйте, skeptik_, Вы писали:
LVV>>>>>Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней. CC>>>>Дык это понятно. Почему предпочтительней? V>>>Потому что ссылка инициализируется один раз, и потом не менеятся, указатель же может указывать на различные объекты в течении жизни, или может не указывать вообще ни на что(неинициализирован), поэтому при передаче параметров через указатели приходится проверять их на ноль, но и это не избавит от возможных ошибок, так как указатель может указывать на "мусор". Ссылки лишины этих недостатков.
_>>Ссылка прежде всего плоха тем, что не даёт ясности относительно вопроса кто владеет объектом и должен его удалять. LVV>Как это не дает? как раз передача по ссылке говорит о том, что объектом владеет вызывающая функция. Передача по ссылке никогда не предполагает удаление объекта. LVV>Что-то вы про ссылке не все понимаете.
Очепятался. Естественно указатель имелся в виду...
Здравствуйте, CoolCmd, Вы спрашивали про ссылки VS указатели:
Ооочень рекомендую книги Мейерса Эффективное использование С++. 50(55) советов... и Наиболее эффективное использование С++. 35 советов.... Так в самом начале второй книги автор резюмирует:
Итак, использование ссылок оправдано,
когда доподлинно известно, что объект ссылки существует,
когда нет необходимости изменять значение ссылки и
при реализации операторов, в которых применение указателей нежелательно из-за синтаксических требований.
Во всех других случаях используйте указатели.
Я уже писал раньше, что в этих книгах «есть ответы на вопросы, которые могли и не придти в голову». Там весьма подробно рассмотрены и те проблемы, на которые указали вам TheBeard, Юрий Жмеренецкий, Кодт: [lr]value, срезка, временные локальные объекты и т.п.
Re[3]: Вызов нескольких derived classes из массива
Здравствуйте, CoolCmd, Вы писали:
CC>Неее, в моем случае — это стрелять из пушки по микробам.
shared_ptr "упрощает жизнь", потому что отслеживает удаление объектов, если оно требуется, конечно.
Но еще проще тот же код будет выглядеть с помощью бустовских контейнеров указателей, которые опять-таки автоматически удалят свое содержимое в деструкторе.