Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Редкая, но возможная грабля, наследование от класса без виртуальных ф 
:(
    Опции темы
FunnyFalcon
Дата 13.12.2006, 15:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 27.3.2006

Репутация: нет
Всего: 7



Код

#include <cstdio>

class A {
    int i;
};

class B: public A {
    int j;
    virtual void d(){}
};

int main(){
    B* b = new B();
    A* a = b;
    printf("%p %p\n", a, b);
    delete a;
    return 0;
};

Код

yura@falcon:~/Temp/C$ c++ inherit.cpp
yura@falcon:~/Temp/C$ a.out
0x804a00c 0x804a008
*** glibc detected *** free(): invalid pointer: 0x0804a00c ***
Aborted

g++ 3.4.6, 4.0.x

Это известная фича? А как в других компиляторах?

PM MAIL   Вверх
Sartorius
Дата 13.12.2006, 16:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1568
Регистрация: 18.7.2006
Где: Ivory tower

Репутация: 8
Всего: 37



 А ты попробуй dynamic_cast-ом B в delete преобразовать... Останется еггог?
PM MAIL ICQ   Вверх
FunnyFalcon
Дата 13.12.2006, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 27.3.2006

Репутация: нет
Всего: 7



dinamic_cast может и сработает. 
Но допустим, мы не знаем, на объект какого класса a на самом деле ссылается? (А иначе зачем нам наследование?)
PM MAIL   Вверх
Fazil6
Дата 13.12.2006, 18:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1653
Регистрация: 3.5.2006
Где: Минск

Репутация: 35
Всего: 60



а в чем собственно фича?
по моему все правильно, как и должно было быть

Добавлено @ 18:27 
добавь в A
Код

public:
    virtual ~A(){};

и ексепшена не будет
PM MAIL   Вверх
Daevaorn
Дата 13.12.2006, 18:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: 51
Всего: 70



Цитата(FunnyFalcon @  13.12.2006,  16:55 Найти цитируемый пост)
Это известная фича? 

Это известная ошибка начинающих разработчиков на C++
PM MAIL WWW   Вверх
Sartorius
Дата 13.12.2006, 19:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1568
Регистрация: 18.7.2006
Где: Ivory tower

Репутация: 8
Всего: 37



Daevaorn, точна smile  деструктора то виртуального нет))
PM MAIL ICQ   Вверх
FunnyFalcon
Дата 14.12.2006, 14:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 27.3.2006

Репутация: нет
Всего: 7



Проблема в том, что вообще ничего виртуального нет в классе A.
И поэтому не выделяется указатель на виртуальную таблицу.
А когда наследуем и создаём виртуальный метод, то указатель на вирт.таблицу добавляется в начало.
Для чего я и распечатывал значения указателей - они разные, 
и именно поэтому и выскакивает ошибка - я пытаюсь удалить по неправильной ссылке.

Первый вопрос у меня возник по-этому поводу - ну почему указатель выртуальной таблицы добавляется в начало? 
добавься он после A.i, ошибки не было бы.
Вот я и спрашиваю - все компиляторы в данной ситуации ведут себя так же?

Идея была использовать не чистый С++, реализовать альтернативу виртуальной таблице. 
Но найдется программер, который отнаследует и приляпает виртуальный метод. И что? Тут же всё пойдёт насмарку?
Потому-что компилятор, видите ли, любит, чтобы таблица всегда была сначала?

Се ля ви (такова жизнь).

Это не наезд. Я действительно новичок в С++. Просто есть вещи, не до конца подчиняющиеся (моей) логике.
PM MAIL   Вверх
Romikgy
Дата 14.12.2006, 15:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: 8
Всего: 146



имхо некоректный код
воть немного подправил для наглядности
Код

#include <cstdlib>
#include <iostream>

using namespace std;
class A {
    int i;
    public:
    A(){cout<<"Constr A()\n";}
    ~A(){cout<<"Destr A()\n";}
};
class B: public A {
    int j;
    virtual void d(){}
    public:
    B(){cout<<"Constr B()\n";}
    virtual
    ~B(){cout<<"Destr B()\n";}
};
int main(int argc, char *argv[])
{
    //////////////////////////////////////
    B* b = new B();
    A* a = b;
    printf("%p %p\n", a, b);
    delete a;
    /////////////////////////////////////////
    system("PAUSE");
    return EXIT_SUCCESS;
}

посмотри что выдает!


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
FunnyFalcon
Дата 14.12.2006, 18:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 27.3.2006

Репутация: нет
Всего: 7



Код

yura@falcon:~/Temp/C$ g++ -o inherit1 inherit1.cpp
yura@falcon:~/Temp/C$ inherit1
Constr A()
Constr B()
0x804b00c 0x804b008
Destr A()
*** glibc detected *** free(): invalid pointer: 0x0804b00c ***
Aborted


gcc 3.4.6. А у тебя какой компилятор?

PM MAIL   Вверх
Romikgy
Дата 14.12.2006, 19:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: 8
Всего: 146



gcc 3.4.2 (только под винду)
Код

Constr A()
Constr B()
003D3FD4 003D3FD0
Destr A()


FunnyFalcon, так ты видишь в чем ошибка?


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
Fazil6
Дата 14.12.2006, 21:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1653
Регистрация: 3.5.2006
Где: Минск

Репутация: 35
Всего: 60



Цитата

FunnyFalcon, так ты видишь в чем ошибка?

и в чем же? о какой ошибке идет речь?
PM MAIL   Вверх
FunnyFalcon
Дата 15.12.2006, 09:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 27.3.2006

Репутация: нет
Всего: 7



Код

*** glibc detected *** free(): invalid pointer: 0x0804b00c ***
Aborted

По-моему это довольно весомая ошибка. Или я не прав?

Программа скомпиленная вашим компилятором этой ошибки не выдаёт. Но вот это мне подсказывает, что в большой программе могут возникнуть большие трудности:
Цитата

Код

003D3FD4 003D3FD0


УКАЗАТЕЛИ РАЗНЫЕ!!!! И что тогда удалает delete? Какую память освобождает?

PM MAIL   Вверх
Fazil6
Дата 15.12.2006, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1653
Регистрация: 3.5.2006
Где: Минск

Репутация: 35
Всего: 60



Цитата(FunnyFalcon @  15.12.2006,  09:32 Найти цитируемый пост)
По-моему это довольно весомая ошибка. Или я не прав?

Программа скомпиленная вашим компилятором этой ошибки не выдаёт. Но вот это мне подсказывает, что в большой программе могут возникнуть большие трудности

любой компилер здесь должен вызывать ошибку.
Я не врубаюсь на что намекает Romikgy и что он хочет своим примером показать. 
Цитата(FunnyFalcon @  15.12.2006,  09:32 Найти цитируемый пост)
УКАЗАТЕЛИ РАЗНЫЕ!!!! И что тогда удалает delete? Какую память освобождает?

значения указателей разные потому, что здесь компиллятор приводит из типа B* в А* и при удалении  а он естественно вызывеет его деструктор так как а имеет тип А*, а фактически объект имеет тип В и должен быть вызван его деструктор и чтобы в такой ситуации вызывался правильный деструктор все деструкторы должны быть виртуальными, чтобы выбирался деструктор не по типу, а по фактическому объекту.

PM MAIL   Вверх
Romikgy
Дата 15.12.2006, 12:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: 8
Всего: 146



Цитата(Fazil6 @  15.12.2006,  09:47 Найти цитируемый пост)
Я не врубаюсь на что намекает Romikgy


Цитата(Fazil6 @  15.12.2006,  09:47 Найти цитируемый пост)
значения указателей разные потому, что здесь компиллятор приводит из типа B* в А* и при удалении  а он естественно вызывеет его деструктор так как а имеет тип А*, а фактически объект имеет тип В и должен быть вызван его деструктор и чтобы в такой ситуации вызывался правильный деструктор все деструкторы должны быть виртуальными, чтобы выбирался деструктор не по типу, а по фактическому объекту.

вот на это и намекал! (неправильная работа с указателями)
Цитата(FunnyFalcon @  15.12.2006,  08:32 Найти цитируемый пост)
003D3FD4 003D3FD0

на это как то не обратил внимание smile
хотя вроде объяснили

PS правда не понятно , ведь это неявное преобразование указателей!!!
в C++ Builder 6 такого преобразования нет , указатели одни и теже!
Код

Constr A()
Constr B()
008F5BD8 008F5BD8
Destr A()



--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
FunnyFalcon
Дата 15.12.2006, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 27.3.2006

Репутация: нет
Всего: 7



Цитата(Romikgy @  15.12.2006,  12:43 Найти цитируемый пост)
PS правда не понятно , ведь это неявное преобразование указателей!!!
в C++ Builder 6 такого преобразования нет , указатели одни и теже!
Код

Constr A()
Constr B()
008F5BD8 008F5BD8
Destr A()


Значит C++Builder 6 в данном вопросе - наиболее логичный компилятор.
А как будет выглядеть результат работы следующего кода:
Код

#include <cstdlib>
#include <iostream>
using namespace std;
class A {
    public:
    int i;
    A(){cout<<"Constr A()\n";}
    ~A(){cout<<"Destr A()\n";}
};
class B: public A {
    public:
    int j;
    B(){cout<<"Constr B()\n";}
    virtual
    ~B(){cout<<"Destr B()\n";}
};
int main(int argc, char *argv[])
{
    //////////////////////////////////////
    B* b = new B();
    b->i = 1;
    b->j = 2;
    int* ar = reinterpret_cast<int*>b;
    printf("%i %i %i\n", ar[0],ar[1],ar[2]);
    delete b;
    /////////////////////////////////////////
    return EXIT_SUCCESS;
}


На gcc-3.4.6 вышло:
Код

Constr A()
Constr B()
134516040 1 2
Destr B()
Destr A()

Откуда видим, что указатель на в. таблицу приляпался к началу.
Видимо на С++Builder-е будет что-то вроде
Код

Constr A()
Constr B()
1 134516040 2
Destr B()
Destr A()

Пришлёшь результат?
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0895 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.