Вызов нескольких derived classes из массива
От: CoolCmd Россия  
Дата: 17.03.10 13:23
Оценка:
Добрый!
Вопрос нуба. В проге решил из структуры сделать объекты, что бы всё было как у взрослых дядек. Но ничего не получилось. Вот упрощенный вариант:
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;
}

Как сделать правильно?
простите, я убил небо
Re: Вызов нескольких derived classes из массива
От: TheBeard Россия  
Дата: 17.03.10 13:27
Оценка: 2 (1)
Здравствуйте, 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()} //ошибка -- в массив объктов типа А нельзя помещать В и С;
CC>}

CC>Как сделать правильно?
Re: Вызов нескольких derived classes из массива
От: Юрий Жмеренецкий ICQ 380412032
Дата: 17.03.10 14:02
Оценка: 2 (1) +1
Здравствуйте, 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' является абстрактным. Массив объектов такого класса создать нельзя.
Re: Вызов нескольких derived classes из массива
От: Кодт Россия  
Дата: 17.03.10 14:32
Оценка: 2 (1)
Здравствуйте, CoolCmd, Вы писали:

CC>Как сделать правильно?


Я бы сделал так
std::vector< boost::shared_ptr<A> > arr;
arr.push_back(boost::shared_ptr<A>(new B()));
arr.push_back(boost::shared_ptr<A>(new C()));


Во-первых, избавляемся от необходимости каким-то особым способом отмечать конец массива. У вектора есть 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 из массива
От: CoolCmd Россия  
Дата: 17.03.10 15:17
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

CC>>static A *aa[] = {&B(), &C(), 0 /*маркер конца списка*/};

ЮЖ>Должна быть ошибка компиляции: 'B()' и 'C()' — rvalue, оператор '&' требует lvalue. MSVC должен детектировать эту ошибку с /Za
Понятно, я расширения не отключаю, полезная штука.
А если везде везде везде поставить const, все равно будет ошибка?

CC>>static A aaa[] = {B(), C()};

ЮЖ>Должна быть ошибка компиляции: Класс 'A' является абстрактным. Массив объектов такого класса создать нельзя.
vs2008sp1. Молчит проклятый.

Здравствуйте, Кодт, Вы писали:

К>Я бы сделал так

К>
К>std::vector< boost::shared_ptr<A> > arr;
К>arr.push_back(boost::shared_ptr<A>(new B()));
К>arr.push_back(boost::shared_ptr<A>(new C()));
К>

Неее, в моем случае — это стрелять из пушки по микробам.


TheBeard, Юрий Жмеренецкий, Кодт, спасибо, буду использовать первый варинт, тем более со структурами делал так же.
простите, я убил небо
Re: Передача объекта в функцию
От: CoolCmd Россия  
Дата: 20.03.10 08:26
Оценка:
Еще один вопрос. Часто вижу, что когда нужно передать объект в функцию, то вместо A *a делают A& a. Почему?
простите, я убил небо
Re[2]: Передача объекта в функцию
От: LaptevVV Россия  
Дата: 20.03.10 10:07
Оценка:
Здравствуйте, CoolCmd, Вы писали:

CC>Еще один вопрос. Часто вижу, что когда нужно передать объект в функцию, то вместо A *a делают A& a. Почему?

Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[3]: Передача объекта в функцию
От: CoolCmd Россия  
Дата: 20.03.10 10:45
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней.

Дык это понятно. Почему предпочтительней?
простите, я убил небо
Re[4]: Передача объекта в функцию
От: v2kochetov Россия  
Дата: 20.03.10 11:14
Оценка: 1 (1) +1
Здравствуйте, CoolCmd, Вы писали:

CC>Здравствуйте, LaptevVV, Вы писали:


LVV>>Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней.

CC>Дык это понятно. Почему предпочтительней?
Потому что ссылка инициализируется один раз, и потом не менеятся, указатель же может указывать на различные объекты в течении жизни, или может не указывать вообще ни на что(неинициализирован), поэтому при передаче параметров через указатели приходится проверять их на ноль, но и это не избавит от возможных ошибок, так как указатель может указывать на "мусор". Ссылки лишины этих недостатков.
... << RSDN@Home 1.2.0 alpha 4 rev. 1464>>
Re[5]: Передача объекта в функцию
От: skeptik_  
Дата: 20.03.10 11:27
Оценка: 1 (1)
Здравствуйте, v2kochetov, Вы писали:

V>Здравствуйте, CoolCmd, Вы писали:


CC>>Здравствуйте, LaptevVV, Вы писали:


LVV>>>Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней.

CC>>Дык это понятно. Почему предпочтительней?
V>Потому что ссылка инициализируется один раз, и потом не менеятся, указатель же может указывать на различные объекты в течении жизни, или может не указывать вообще ни на что(неинициализирован), поэтому при передаче параметров через указатели приходится проверять их на ноль, но и это не избавит от возможных ошибок, так как указатель может указывать на "мусор". Ссылки лишины этих недостатков.

Ссылка прежде всего плоха тем, что не даёт ясности относительно вопроса кто владеет объектом и должен его удалять.
Re[6]: Передача объекта в функцию
От: LaptevVV Россия  
Дата: 20.03.10 13:44
Оценка:
Здравствуйте, skeptik_, Вы писали:

LVV>>>>Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней.

CC>>>Дык это понятно. Почему предпочтительней?
V>>Потому что ссылка инициализируется один раз, и потом не менеятся, указатель же может указывать на различные объекты в течении жизни, или может не указывать вообще ни на что(неинициализирован), поэтому при передаче параметров через указатели приходится проверять их на ноль, но и это не избавит от возможных ошибок, так как указатель может указывать на "мусор". Ссылки лишины этих недостатков.

_>Ссылка прежде всего плоха тем, что не даёт ясности относительно вопроса кто владеет объектом и должен его удалять.

Как это не дает? как раз передача по ссылке говорит о том, что объектом владеет вызывающая функция. Передача по ссылке никогда не предполагает удаление объекта.
Что-то вы про ссылке не все понимаете.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[7]: Передача объекта в функцию
От: skeptik_  
Дата: 20.03.10 16:13
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, skeptik_, Вы писали:


LVV>>>>>Первый вариант — передача указателя, а второй — ссылки на объект. В С++ второй вариант предпочтительней.

CC>>>>Дык это понятно. Почему предпочтительней?
V>>>Потому что ссылка инициализируется один раз, и потом не менеятся, указатель же может указывать на различные объекты в течении жизни, или может не указывать вообще ни на что(неинициализирован), поэтому при передаче параметров через указатели приходится проверять их на ноль, но и это не избавит от возможных ошибок, так как указатель может указывать на "мусор". Ссылки лишины этих недостатков.

_>>Ссылка прежде всего плоха тем, что не даёт ясности относительно вопроса кто владеет объектом и должен его удалять.

LVV>Как это не дает? как раз передача по ссылке говорит о том, что объектом владеет вызывающая функция. Передача по ссылке никогда не предполагает удаление объекта.
LVV>Что-то вы про ссылке не все понимаете.
Очепятался. Естественно указатель имелся в виду...
Re[4]: Передача объекта в функцию
От: Kirikaza Россия kirikaza.ru
Дата: 21.03.10 19:16
Оценка: 2 (2)
Здравствуйте, CoolCmd, Вы спрашивали про ссылки VS указатели:

Ооочень рекомендую книги Мейерса Эффективное использование С++. 50(55) советов... и Наиболее эффективное использование С++. 35 советов.... Так в самом начале второй книги автор резюмирует:

Итак, использование ссылок оправдано,

Во всех других случаях используйте указатели.


Я уже писал раньше, что в этих книгах «есть ответы на вопросы, которые могли и не придти в голову». Там весьма подробно рассмотрены и те проблемы, на которые указали вам TheBeard, Юрий Жмеренецкий, Кодт: [lr]value, срезка, временные локальные объекты и т.п.
Re[3]: Вызов нескольких derived classes из массива
От: alex-t  
Дата: 25.03.10 16:37
Оценка:
Здравствуйте, CoolCmd, Вы писали:

CC>Неее, в моем случае — это стрелять из пушки по микробам.


shared_ptr "упрощает жизнь", потому что отслеживает удаление объектов, если оно требуется, конечно.
Но еще проще тот же код будет выглядеть с помощью бустовских контейнеров указателей, которые опять-таки автоматически удалят свое содержимое в деструкторе.

boost::ptr_vector<A> a;

a.push_back(new B());
a.push_back(new C());

a[0].VFunc();
a[1].VFunc();
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.