Вызов виртуального метода для класса
От: Chez Россия  
Дата: 19.10.04 07:24
Оценка: :)
Есть класс наследованный от CObject. Нужно вызвать виртуальный метод этого класса, не имея экземпляра класса (этот метод не использует this). Как это сделать?

Понимаю, что нужно каким-то образом получить vtbl этого класса и найти в нём смещение нужного метода... Но вот как?

А нужно что-то вроде:
class CAssert
{
public:
    template<class class_name, class objectT>
    void KindOf(objectT* pObject)
    { ASSERT(pObject->IsKindOf( ((class_name*)NULL)->GetRuntimeClass() )); }
                                        // только это не работает
};


Помогите плз
Chez, ICQ# 161095094
Re: Вызов виртуального метода для класса
От: Vamp Россия  
Дата: 19.10.04 07:29
Оценка:
Естественно это не работает. Разыменовывать нулевые указатели запрещено.
Лучше всего — отказаться от убогой информации о типе времени выполнения на методах из кайнд оф и перейти к стандартному typeid.
Да здравствует мыло душистое и веревка пушистая.
Re[2]: Вызов виртуального метода для класса
От: Chez Россия  
Дата: 19.10.04 07:34
Оценка:
Здравствуйте, Vamp, Вы писали:

V>Естественно это не работает. Разыменовывать нулевые указатели запрещено.

V>Лучше всего — отказаться от убогой информации о типе времени выполнения на методах из кайнд оф и перейти к стандартному typeid.
Не, RTTI не катит.
Chez, ICQ# 161095094
Re[3]: Вызов виртуального метода для класса
От: Lorenzo_LAMAS  
Дата: 19.10.04 07:37
Оценка: :)
C>Не, RTTI не катит.

Вызывать нестатическую функцию-член без объекта тоже никуда не катит.
Of course, the code must be complete enough to compile and link.
Re: Вызов виртуального метода для класса
От: korzhik Россия  
Дата: 19.10.04 07:38
Оценка: +1
Здравствуйте, Chez, Вы писали:

C>
C>class CAssert
C>{
C>public:
C>    template<class class_name, class objectT>
C>    void KindOf(objectT* pObject)
C>    { ASSERT(pObject->IsKindOf( ((class_name*)NULL)->GetRuntimeClass() )); }
C>                                        // только это не работает
C>};
C>


про виртуальную функцию не понял, а чтобы вышеприведённый кусок кода заработал, пиши так:
//...
{ ASSERT(pObject->IsKindOf( RUNTIME_CLASS(class_name)); }
Re[2]: Вызов виртуального метода для класса
От: Chez Россия  
Дата: 19.10.04 07:44
Оценка:
Здравствуйте, korzhik, Вы писали:

K>про виртуальную функцию не понял, а чтобы вышеприведённый кусок кода заработал, пиши так:

Вызвать вирутальную функцию с this = абы_шо, т.е. недействительный экземпляр.
K>
K>//...
K>{ ASSERT(pObject->IsKindOf( RUNTIME_CLASS(class_name)); }
K>

В шаблоне это работать не будет.
Макрос RUNTIME_CLASS(class_name) разворачиватся в ...class##class_name... В результате ошибка

error C2039: 'classclass_name' : is not a member of 'CWnd'

Chez, ICQ# 161095094
Re[3]: Вызов виртуального метода для класса
От: korzhik Россия  
Дата: 19.10.04 07:46
Оценка:
Здравствуйте, Chez, Вы писали:

C>В шаблоне это работать не будет.

C>Макрос RUNTIME_CLASS(class_name) разворачиватся в ...class##class_name... В результате ошибка
C>

C>error C2039: 'classclass_name' : is not a member of 'CWnd'


да, действительно
что то сразу не сообразил, что у вас там шаблон
ну что ж будем думать...
Re: Вызов виртуального метода для класса
От: JakeS  
Дата: 19.10.04 07:48
Оценка:
Здравствуйте, Chez, Вы писали:

C>Есть класс наследованный от CObject. Нужно вызвать виртуальный метод этого класса, не имея экземпляра класса (этот метод не использует this). Как это сделать?


C>Понимаю, что нужно каким-то образом получить vtbl этого класса и найти в нём смещение нужного метода... Но вот как?


C>А нужно что-то вроде:

C>
C>class CAssert
C>{
C>public:
C>    template<class class_name, class objectT>
C>    void KindOf(objectT* pObject)
C>    { ASSERT(pObject->IsKindOf( ((class_name*)NULL)->GetRuntimeClass() )); }
C>                                        // только это не работает
C>};
C>


C>Помогите плз


что за глупости? какой виртуальный метод если объекта нет? Насколько я понял тебе нужен просто static метод.
Re[2]: Вызов виртуального метода для класса
От: Chez Россия  
Дата: 19.10.04 07:52
Оценка:
JS>что за глупости? какой виртуальный метод если объекта нет? Насколько я понял тебе нужен просто static метод.
Это не static метод, в том то всё и дело, а virtual. Но я хотел бы его вызвать, будто бы он static.
Замечу ещё раз, что код этого метода не использует this.
Chez, ICQ# 161095094
Re: Вызов виртуального метода для класса
От: Аноним  
Дата: 19.10.04 08:10
Оценка: +1
Здравствуйте, Chez, Вы писали:

C>Есть класс наследованный от CObject. Нужно вызвать виртуальный метод этого класса, не имея экземпляра класса (этот метод не использует this). Как это сделать?


C>Понимаю, что нужно каким-то образом получить vtbl этого класса и найти в нём смещение нужного метода... Но вот как?


C>А нужно что-то вроде:

C>
C>class CAssert
C>{
C>public:
C>    template<class class_name, class objectT>
C>    void KindOf(objectT* pObject)
C>    { ASSERT(pObject->IsKindOf( ((class_name*)NULL)->GetRuntimeClass() )); }
C>                                        // только это не работает
C>};
C>


C>Помогите плз


Виртуальные метод так вызвать нельзя, потому что виртуальных методов "не использующих this" не существует. this используется реализацией вызова виртуального метода, так как необходимо обратиться к виртуальной таблице, ссылка на которую находится в теле объекта и на нее указывает this. Через (class_name*)NULL можно вызвать невиртуальный метод, не использующий this. Тогда, правда, такой метод следовало бы сделать статическим, раз ему this не нужен.
Re[3]: Вызов виртуального метода для класса
От: MaximE Великобритания  
Дата: 19.10.04 08:12
Оценка:
Chez wrote:

> JS>что за глупости? какой виртуальный метод если объекта нет? Насколько я понял тебе нужен просто static метод.

> Это не static метод, в том то всё и дело, а virtual. Но я хотел бы его вызвать, будто бы он static.
> Замечу ещё раз, что код этого метода не использует this.

А что это за метод (вообще, в c++ не существует методов, только ф-ции-члены ), кто его создатель — ты или творцы MFC?

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9 gamma
Re[4]: Вызов виртуального метода для класса
От: Vamp Россия  
Дата: 19.10.04 08:17
Оценка:
Это МФСишное убожество времент 4 версии компилятора визуал си.
А что значит "в c++ не существует методов, только ф-ции-члены"? Функции-члены в С++ и называются методами. Или сообщениями даже
Да здравствует мыло душистое и веревка пушистая.
Re[4]: Вызов виртуального метода для класса
От: JakeS  
Дата: 19.10.04 08:21
Оценка: :)
Здравствуйте, MaximE, Вы писали:

ME>Chez wrote:


>> JS>что за глупости? какой виртуальный метод если объекта нет? Насколько я понял тебе нужен просто static метод.

>> Это не static метод, в том то всё и дело, а virtual. Но я хотел бы его вызвать, будто бы он static.
>> Замечу ещё раз, что код этого метода не использует this.

ME>А что это за метод (вообще, в c++ не существует методов, только ф-ции-члены ), кто его создатель — ты или творцы MFC?


Ну ты просто гений. в c++ не существует ни методов ни функций членов, поскольку стандарт на английском писан. так что же теперь по русски не разговаривать?

ME>--

ME>Maxim Yegorushkin
Re[3]: Вызов виртуального метода для класса
От: Кодт Россия  
Дата: 19.10.04 08:30
Оценка:
Здравствуйте, Chez, Вы писали:

JS>>что за глупости? какой виртуальный метод если объекта нет? Насколько я понял тебе нужен просто static метод.

C>Это не static метод, в том то всё и дело, а virtual. Но я хотел бы его вызвать, будто бы он static.
C>Замечу ещё раз, что код этого метода не использует this.

Уже сама по себе виртуальность использует this.

А тебе, видимо, нужно другое: виртуальный метод адресации к статическому
typedef int (*Fun)(int);

class Foo
{
public:
  virtual Fun have_fun() const { return my_fun; }
private:
  static int my_fun(int x) { return x*2; }
};

class Bar : public Foo
{
public:
  Fun have_fun() const { return my_own_fun; }
private:
  static int my_own_fun(int x) { return x*x; }
};

void test_fun(Fun fun)
{
  cout << fun(10) << endl;
}

void test_obj(Foo* p)
{
  test_fun(p->have_fun());
}

main()
{
  Foo *a = new Foo(), *b = new Bar();
  test_obj(a);
  test_obj(b);
  delete a; delete b;
}
Перекуём баги на фичи!
Re[5]: Вызов виртуального метода для класса
От: MaximE Великобритания  
Дата: 19.10.04 08:43
Оценка:
Vamp wrote:

> А что значит "в c++ не существует методов, только ф-ции-члены"? Функции-члены в С++ и называются методами. Или сообщениями даже


http://groups.google.com/groups?threadm=bisnp7%24a4k%241%40hercules.btinternet.com

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9 gamma
Re[4]: Вызов виртуального метода для класса
От: Chez Россия  
Дата: 19.10.04 09:00
Оценка:
ME>А что это за метод (вообще, в c++ не существует методов, только ф-ции-члены ), кто его создатель — ты или творцы MFC?

ME>--

ME>Maxim Yegorushkin
Творцы MFC. CObject::GetRuntimeClass
Chez, ICQ# 161095094
Re[2]: Вызов виртуального метода для класса
От: Chez Россия  
Дата: 19.10.04 09:00
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Виртуальные метод так вызвать нельзя, потому что виртуальных методов "не использующих this" не существует. this используется реализацией вызова виртуального метода, так как необходимо обратиться к виртуальной таблице, ссылка на которую находится в теле объекта и на нее указывает this. Через (class_name*)NULL можно вызвать невиртуальный метод, не использующий this. Тогда, правда, такой метод следовало бы сделать статическим, раз ему this не нужен.


Ну почему же нет? Машинный код виртуального метода ничем не отличается от обычной функции. Нужно только определить, где в памяти находится этот метод и вызвать его, в параметре EBX указав 0 (this — не используется).

Я знаю, что это возможно, но не знаю как. Догадываюсь, что нужно что-то мутить с vtbl.
Chez, ICQ# 161095094
Re[4]: Вызов виртуального метода для класса
От: Chez Россия  
Дата: 19.10.04 09:04
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Уже сама по себе виртуальность использует this.

Вот я и думаю если туда подсунуть какой-нить суррогатный this...
К>А тебе, видимо, нужно другое: виртуальный метод адресации к статическому
Я бы это обязательно добавил, если бы проектировал MFC.
GetRuntimeClass() — виртуальный, и статического аналога нет
Chez, ICQ# 161095094
Re[3]: аноним 2
От: Аноним  
Дата: 19.10.04 09:07
Оценка:
C>Ну почему же нет? Машинный код виртуального метода ничем не отличается от обычной функции. Нужно только определить, где в памяти находится этот метод и вызвать его, в параметре EBX указав 0 (this — не используется).

Чтоб найти втбл как раз this и нужен.
Re[3]: Вызов виртуального метода для класса
От: Аноним  
Дата: 19.10.04 09:13
Оценка: 4 (2) +1
Здравствуйте, Chez, Вы писали:

C>Здравствуйте, <Аноним>, Вы писали:


А>>Виртуальные метод так вызвать нельзя, потому что виртуальных методов "не использующих this" не существует. this используется реализацией вызова виртуального метода, так как необходимо обратиться к виртуальной таблице, ссылка на которую находится в теле объекта и на нее указывает this. Через (class_name*)NULL можно вызвать невиртуальный метод, не использующий this. Тогда, правда, такой метод следовало бы сделать статическим, раз ему this не нужен.


C>Ну почему же нет? Машинный код виртуального метода ничем не отличается от обычной функции. Нужно только определить, где в памяти находится этот метод и вызвать его, в параметре EBX указав 0 (this — не используется).


C>Я знаю, что это возможно, но не знаю как. Догадываюсь, что нужно что-то мутить с vtbl.


Я ж говорю — vtbl можно найти только если есть объект, т.к. его тело содержит ссылку на нее. Если нужно невиртуально вызвать метод, объявленный виртуальным, то в вызове нужно явно указать имя класса:


struct C1
{
virtual int Met() { return 1; }
};

struct C2 : public C1
{
virtual int Met() { return 2; }
};


int _tmain(int argc, _TCHAR* argv[])
{
// эти два вызова работают: невиртуальный вызов виртуальной функции
int i2=((C2*)0)->C2::Met();
int i1=((C2*)0)->C1::Met();
assert( i2==2);
assert( i1==1);

int ifail=((C2*)0)->Met(); // здесь падает: виртуальный вызов через null-указатель
return 0;


}
Re[4]: Вызов виртуального метода для класса
От: Chez Россия  
Дата: 19.10.04 09:21
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Я ж говорю — vtbl можно найти только если есть объект, т.к. его тело содержит ссылку на нее. Если нужно невиртуально вызвать метод, объявленный виртуальным, то в вызове нужно явно указать имя класса:

Именно! Огромное Вам спасибо! Это то, что мне нужно было!

template<class class_name, class objectT>
void AssertKindOf(objectT* a)
{
    ASSERT(a->IsKindOf( ((class_name*)NULL)->class_name::GetRuntimeClass() ));
}
— работает!
Chez, ICQ# 161095094
Re[3]: Вызов виртуального метода для класса
От: jazzer Россия Skype: enerjazzer
Дата: 19.10.04 09:27
Оценка:
Здравствуйте, Chez, Вы писали:

C>Здравствуйте, <Аноним>, Вы писали:


А>>Виртуальные метод так вызвать нельзя, потому что виртуальных методов "не использующих this" не существует. this используется реализацией вызова виртуального метода, так как необходимо обратиться к виртуальной таблице, ссылка на которую находится в теле объекта и на нее указывает this. Через (class_name*)NULL можно вызвать невиртуальный метод, не использующий this. Тогда, правда, такой метод следовало бы сделать статическим, раз ему this не нужен.


C>Ну почему же нет? Машинный код виртуального метода ничем не отличается от обычной функции. Нужно только определить, где в памяти находится этот метод и вызвать его, в параметре EBX указав 0 (this — не используется).


C>Я знаю, что это возможно, но не знаю как. Догадываюсь, что нужно что-то мутить с vtbl.


Потому что Стандарт С++ не оговаривает машинный код методов, более того, в Стандарте нет понятия виртуальной таблицы. (попробуй поискать в тексте Стандарта vtbl или vmt на досуге)
Ты оперируешь терминами конкретной реализации, выходящими за пределы Стандарта, а задаешь вопрос о решении в рамках Стандарта.
Решения в рамках Стандарта не существует.
Существуют платформенно-зависимые решения, начиная с "определенного" неопределенного поведения и кончая asm.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Вызов виртуального метода для класса
От: Chez Россия  
Дата: 19.10.04 09:31
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Потому что Стандарт С++ не оговаривает машинный код методов, более того, в Стандарте нет понятия виртуальной таблицы. (попробуй поискать в тексте Стандарта vtbl или vmt на досуге)

J>Ты оперируешь терминами конкретной реализации, выходящими за пределы Стандарта, а задаешь вопрос о решении в рамках Стандарта.
J>Решения в рамках Стандарта не существует.
J>Существуют платформенно-зависимые решения, начиная с "определенного" неопределенного поведения и кончая asm.
Ок.
А это
Автор:
Дата: 19.10.04
— решение в рамках стандарта?
Chez, ICQ# 161095094
Re[5]: Вызов виртуального метода для класса
От: Кодт Россия  
Дата: 19.10.04 09:32
Оценка: +1
Здравствуйте, Chez, Вы писали:

C>Именно! Огромное Вам спасибо! Это то, что мне нужно было!


Вот так и приходится хакать, вместо того, чтобы в MFC с самого начала делали бы пару — статический метод и виртуальный. И не пришлось бы им тогда выделываться с макросом...
Перекуём баги на фичи!
Re[6]: Вызов виртуального метода для класса
От: Аноним  
Дата: 19.10.04 09:36
Оценка:
Здравствуйте, Кодт, Вы писали:

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


C>>Именно! Огромное Вам спасибо! Это то, что мне нужно было!


К>Вот так и приходится хакать, вместо того, чтобы в MFC с самого начала делали бы пару — статический метод и виртуальный. И не пришлось бы им тогда выделываться с макросом...


Ну не проинтуичили в микрософте сразу. Когда писался CRuntimeClass мелкомягкий компилятор не токмо что шаблоны, но и исключения не поддерживал
Re[5]: Вызов виртуального метода для класса
От: jazzer Россия Skype: enerjazzer
Дата: 19.10.04 09:54
Оценка:
Здравствуйте, Chez, Вы писали:

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


J>>Потому что Стандарт С++ не оговаривает машинный код методов, более того, в Стандарте нет понятия виртуальной таблицы. (попробуй поискать в тексте Стандарта vtbl или vmt на досуге)

J>>Ты оперируешь терминами конкретной реализации, выходящими за пределы Стандарта, а задаешь вопрос о решении в рамках Стандарта.
J>>Решения в рамках Стандарта не существует.
J>>Существуют платформенно-зависимые решения, начиная с "определенного" неопределенного поведения и кончая asm.
C>Ок.
C>А это
Автор:
Дата: 19.10.04
— решение в рамках стандарта?


конечно же нет.
5.2.5/3
If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2;

соответственно запись
((C2*)0)->Met();

означает
(*(C2*)0).Met();

т.е. разыменование нулевого указателя — неопределенное поведение
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: Вызов виртуального метода для класса
От: Chez Россия  
Дата: 19.10.04 10:05
Оценка:
Здравствуйте, jazzer, Вы писали:

J>конечно же нет.

J>5.2.5/3
J>If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2;

J>соответственно запись
((C2*)0)->Met();

J>означает
J>(*(C2*)0).Met();
J>

J>т.е. разыменование нулевого указателя — неопределенное поведение
Хм... А что собственно вы понимаете под "разыменовыванием"? Операторы * и -> ?
Если так, то ну и что? Чтения из нулевого адреса не происходит, записи тоже. В данном случае лишь this-у присваивается NULL.

Я конечно понимаю, что теоретически реализация может быть иной, и запись\чтение таки произойдёт и приведёт к краху.
Но ума не приложу, где такое может произойти на практике.
Chez, ICQ# 161095094
Re[6]: Вызов виртуального метода для класса
От: Аноним  
Дата: 19.10.04 10:09
Оценка:
Здравствуйте, jazzer, Вы писали:

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


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


J>>>Потому что Стандарт С++ не оговаривает машинный код методов, более того, в Стандарте нет понятия виртуальной таблицы. (попробуй поискать в тексте Стандарта vtbl или vmt на досуге)

J>>>Ты оперируешь терминами конкретной реализации, выходящими за пределы Стандарта, а задаешь вопрос о решении в рамках Стандарта.
J>>>Решения в рамках Стандарта не существует.
J>>>Существуют платформенно-зависимые решения, начиная с "определенного" неопределенного поведения и кончая asm.
C>>Ок.
C>>А это
Автор:
Дата: 19.10.04
— решение в рамках стандарта?


J>конечно же нет.

J>5.2.5/3
J>If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2;

J>соответственно запись
((C2*)0)->Met();

J>означает
J>(*(C2*)0).Met();
J>

J>т.е. разыменование нулевого указателя — неопределенное поведение

Работая с MFC нет смысла особо заморачиваться насчет стандарта. Как говаривал старик Гете: "Суха теория, мой друг, а древо жизни пышно зеленеет". Вряд ли компилятор при обработке вызова E1->E2() сначала разыменовывает Е1. Обращение по указателю E1 нужно только при виртуальной вызове. Иначе этот указатель просто (без какого-либо анализа) передается методу в качестве скрытого параметра this.
На большинстве стандартных вычислительных архитекрур imho это будет работать. Хотя в архитектурах типа .NET. возможно и нет (сорри за каламбур), но там и MFC нет (снова сорри) — там есть свои средства для доступа к информации о типе во время исполнения (более мощные чем CRuntimeClass в MFC)
Re[7]: Вызов виртуального метода для класса
От: GlebZ Россия  
Дата: 19.10.04 10:20
Оценка:
Здравствуйте, Аноним, Вы писали:

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


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


C>>>Именно! Огромное Вам спасибо! Это то, что мне нужно было!


К>>Вот так и приходится хакать, вместо того, чтобы в MFC с самого начала делали бы пару — статический метод и виртуальный. И не пришлось бы им тогда выделываться с макросом...


А>Ну не проинтуичили в микрософте сразу. Когда писался CRuntimeClass мелкомягкий компилятор не токмо что шаблоны, но и исключения не поддерживал


Да насколько я помню, при MFC 1.0 компилятор вообще не знал, что такое RTTI. После появления последнего, я стараюсь не пользоваться CRuntimeClass. Не вижу смысла разделять MFC классы и не MFC.

С уважением, Gleb
Re[8]: Вызов виртуального метода для класса
От: Аноним  
Дата: 19.10.04 10:32
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Здравствуйте, Аноним, Вы писали:


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


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


C>>>>Именно! Огромное Вам спасибо! Это то, что мне нужно было!


К>>>Вот так и приходится хакать, вместо того, чтобы в MFC с самого начала делали бы пару — статический метод и виртуальный. И не пришлось бы им тогда выделываться с макросом...


А>>Ну не проинтуичили в микрософте сразу. Когда писался CRuntimeClass мелкомягкий компилятор не токмо что шаблоны, но и исключения не поддерживал


GZ>Да насколько я помню, при MFC 1.0 компилятор вообще не знал, что такое RTTI. После появления последнего, я стараюсь не пользоваться CRuntimeClass. Не вижу смысла разделять MFC классы и не MFC.


GZ>С уважением, Gleb


Да, RTTI вообще поддерживается этим компилятором совсем недавно. Следует, однако, иметь в виду, что в CRuntimeClass есть фичи, которые не поддерживаются RTTI, а именно CreateObject, IsDerivedFrom и поддержка CArchive. Нельзя сказать, что без всего этого нельзя обойтись, но очевидно, что RTTI и CRuntimeClass неэквивалентны.
Re[9]: Вызов виртуального метода для класса
От: GlebZ Россия  
Дата: 19.10.04 11:29
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Да, RTTI вообще поддерживается этим компилятором совсем недавно. Следует, однако, иметь в виду, что в CRuntimeClass есть фичи, которые не поддерживаются RTTI, а именно CreateObject, IsDerivedFrom и поддержка CArchive. Нельзя сказать, что без всего этого нельзя обойтись, но очевидно, что RTTI и CRuntimeClass неэквивалентны.


Несколько самозабвенно написал, каюсь, однако почти всегда обхожусь: CreateObject — обычно создается другими способами, IsDerivedFrom — xxx_cast() более быстрые процедуры. Что касается CArchive, то почему-то в последнее время не приходится пользоваться. Проще получается переопределять процедуру загрузки — сохранения из-за сложностей форматов. Это можно сказать является просто особенности тех проектов с применение MFC, которые приходилось делать в последнее время. К тому-же приходится сидеть на нескольких платформах, и отвыкать от MFC заморочек.

С уважением, Gleb.
Re[10]: Вызов виртуального метода для класса
От: Аноним  
Дата: 19.10.04 11:32
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Здравствуйте, Аноним, Вы писали:


А>>Да, RTTI вообще поддерживается этим компилятором совсем недавно. Следует, однако, иметь в виду, что в CRuntimeClass есть фичи, которые не поддерживаются RTTI, а именно CreateObject, IsDerivedFrom и поддержка CArchive. Нельзя сказать, что без всего этого нельзя обойтись, но очевидно, что RTTI и CRuntimeClass неэквивалентны.


GZ>Несколько самозабвенно написал, каюсь, однако почти всегда обхожусь: CreateObject — обычно создается другими способами, IsDerivedFrom — xxx_cast() более быстрые процедуры. Что касается CArchive, то почему-то в последнее время не приходится пользоваться. Проще получается переопределять процедуру загрузки — сохранения из-за сложностей форматов. Это можно сказать является просто особенности тех проектов с применение MFC, которые приходилось делать в последнее время. К тому-же приходится сидеть на нескольких платформах, и отвыкать от MFC заморочек.


GZ>С уважением, Gleb.


Да в общем-то я с Вами полностью согласен.
Re[7]: Вызов виртуального метода для класса
От: jazzer Россия Skype: enerjazzer
Дата: 19.10.04 13:01
Оценка:
Здравствуйте, Chez, Вы писали:

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


J>>конечно же нет.

J>>5.2.5/3
J>>If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2;

J>>соответственно запись
((C2*)0)->Met();

J>>означает
J>>(*(C2*)0).Met();
J>>

J>>т.е. разыменование нулевого указателя — неопределенное поведение
C>Хм... А что собственно вы понимаете под "разыменовыванием"? Операторы * и -> ?
Какая разница, что понимаю я?
Важно, как это определяет Стандарт. А он это понимает как выражение приведения, перед которым стоит символ *.
C>Если так, то ну и что? Чтения из нулевого адреса не происходит, записи тоже. В данном случае лишь this-у присваивается NULL.

Происходит разыменование.
Этого достаточно для неопределенного поведения.
Хотя есть предложения по изменению стандарта в этой части.

C>Я конечно понимаю, что теоретически реализация может быть иной, и запись\чтение таки произойдёт и приведёт к краху.

C>Но ума не приложу, где такое может произойти на практике. :???:

в cint, думаю, это вполне возможно
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[8]: Вызов виртуального метода для класса
От: Lorenzo_LAMAS  
Дата: 19.10.04 13:05
Оценка:
J>в cint, думаю, это вполне возможно

Да, он это не пропустит.
Of course, the code must be complete enough to compile and link.
Re[9]: Вызов виртуального метода для класса
От: Аноним  
Дата: 19.10.04 13:09
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

J>>в cint, думаю, это вполне возможно


L_L>Да, он это не пропустит.


Во-во, во всяких интерпретаторах, типа cint и .NET не будет работать. А на большинстве компиляторов в машинный код — будет. Опять же, если имеем дело с MFC, то пофиг интерпретаторы.
Re[7]: Вызов виртуального метода для класса
От: jazzer Россия Skype: enerjazzer
Дата: 19.10.04 13:37
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Работая с MFC нет смысла особо заморачиваться насчет стандарта.


Бери шире: на VC6.0 вообще не имеет смысл заморачиваться

Удалено избыточное цитирование. -- ПК
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[8]: Вызов виртуального метода для класса
От: Аноним  
Дата: 19.10.04 13:38
Оценка:
Здравствуйте, jazzer, Вы писали:

А>>Работая с MFC нет смысла особо заморачиваться насчет стандарта.


J>Бери шире: на VC6.0 вообще не имеет смысл заморачиваться


Натюрлих

Удалено избыточное цитирование. -- ПК
Re[9]: Вызов виртуального метода для класса
От: erithion aka tyomik  
Дата: 19.10.04 17:06
Оценка: 2 (1)
Здравствуйте, Аноним, Вы писали:

А>>>Работая с MFC нет смысла особо заморачиваться насчет стандарта.


J>>Бери шире: на VC6.0 вообще не имеет смысл заморачиваться


А>Натюрлих


Не знаю как там со стандартом, но большинство известных мне С++ современных компиляторов генерят в этом отношении приблизительно одинаковый код. Вот тест:

class test
{
public:
    void test_fn();
    virtual void virt_fn();
};
void test::test_fn()
{
    return;
}
void test::virt_fn()
{
    return;
}

int _tmain(int argc, _TCHAR* argv[])
{
    test* t = 0;
    (*t).test_fn();
    t->virt_fn();        // Будет креш
    return 0;
}

Вот его асм(сорри за stdInit — ИДА в сигнатурах запуталась). См. комменты после ; :

.text:00401020 _main           proc near               ; CODE XREF: start+16Ep
.text:00401020
.text:00401020 t               = dword ptr -4
.text:00401020
.text:00401020                 push    ebp
.text:00401021                 mov     ebp, esp
.text:00401023                 push    ecx
.text:00401024                 mov     [ebp+t], 0                   ; test* t = 0;
.text:0040102B                 mov     ecx, [ebp+t]
.text:0040102E                 call    ??1_Init_locks@std@@QAE@XZ   ; t->test_fn();
.text:00401033                 mov     eax, [ebp+t]
.text:00401036                 mov     edx, [eax]                   ; edx = this->vftbl; // (*this)
.text:00401038                 mov     ecx, [ebp+t]
.text:0040103B                 call    dword ptr [edx]              ; vftbl[0]() - crash;
.text:0040103D                 xor     eax, eax
.text:0040103F                 mov     esp, ebp
.text:00401041                 pop     ebp
.text:00401042                 retn
.text:00401042 _main           endp


Разница лишь в том как они передают указатели в основном, и насколько они наворочены в оптимизации. Но адресации вирт. методов в асме всегда косвенная регистровая. Где содержимое регистра есть разыменованный this, т.е. как раз vtbl.
Так что есть стандарты, а есть реальные компилеры, которые в этом случае все как один себя и ведут

Удалено избыточное цитирование. -- ПК
... locked in silent monolog ...
Re[10]: Вызов виртуального метода для класса
От: erithion aka tyomik  
Дата: 19.10.04 17:10
Оценка:
Здравствуйте, erithion aka tyomik, Вы писали:

EAT>Так что есть стандарты, а есть реальные компилеры, которые в этом случае все как один себя и ведут


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

Удалено избыточное цитирование. -- ПК
... locked in silent monolog ...
Re[7]: Вызов виртуального метода для класса
От: erithion aka tyomik  
Дата: 19.10.04 17:21
Оценка:
Здравствуйте, Вы писали:

А>На большинстве стандартных вычислительных архитекрур imho это будет работать. Хотя в архитектурах типа .NET. возможно и нет (сорри за каламбур), но там и MFC нет (снова сорри) — там есть свои средства для доступа к информации о типе во время исполнения (более мощные чем CRuntimeClass в MFC)


Но сработае такой вызов:

class test
{
public:
    virtual void virt_fn();
};
void test::virt_fn()
{
    return;
}

int _tmain(int argc, _TCHAR* argv[])
{
    test* t = 0;
    t->test::virt_fn();
    return 0;
}

Тока естесственно указатель на себя будет нулевой, и это равносильно вызову стат. метода...

Удалено избыточное цитирование. -- ПК
... locked in silent monolog ...
Re[11]: Вызов виртуального метода для класса
От: Chez Россия  
Дата: 20.10.04 07:39
Оценка:
Здравствуйте, erithion aka tyomik, Вы писали:

EAT>Забыл упомянуть, что вызов невиртуальных методов всегда происходит непосредственно, по адресу, за исключением сложных случаев наследования, когда невиртуальный метод таки попадает в виртуальную таблицу и вызывается косвенно. Но такие случаи не часты.

А можно пример, когда такое возможно?
Chez, ICQ# 161095094
Re[4]: Вызов виртуального метода для класса
От: Аноним  
Дата: 20.10.04 07:53
Оценка: :))
Здравствуйте, jazzer, Вы писали:

J>Потому что Стандарт С++ не оговаривает машинный код методов, более того, в Стандарте нет понятия виртуальной таблицы. (попробуй поискать в тексте Стандарта vtbl или vmt на досуге)

J>Ты оперируешь терминами конкретной реализации, выходящими за пределы Стандарта, а задаешь вопрос о решении в рамках Стандарта.
J>Решения в рамках Стандарта не существует.
J>Существуют платформенно-зависимые решения, начиная с "определенного" неопределенного поведения и кончая asm.

Аминь.
Re[12]: Вызов виртуального метода для класса
От: erithion aka tyomik  
Дата: 21.10.04 18:17
Оценка:
Здравствуйте, Chez, Вы писали:

C>Здравствуйте, erithion aka tyomik, Вы писали:


EAT>>Забыл упомянуть, что вызов невиртуальных методов всегда происходит непосредственно, по адресу, за исключением сложных случаев наследования, когда невиртуальный метод таки попадает в виртуальную таблицу и вызывается косвенно. Но такие случаи не часты.

C>А можно пример, когда такое возможно?
Пожалуйста:
class a
{
public:
    a()
    {
        printf("a::constructor");
    }
    virtual void fn()
    {
        printf("a::fn");
    }
};
class c: public virtual a
{
public:
    c()
    {
        printf("c::constructor");
    }
    void fn()
    {
        printf("c::fn");
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    c* i = new c();
    i->fn();
    delete i;
    return 0;
}

Вот более или менее понятный разбор того, что происходит в бин. коде:

Кострукторы
.text:00401110     a_constructor   proc near               ; CODE XREF: c_constructor+1Cp
...........................
.text:00401133     a_constructor   endp
.text:004010A0     c_constructor   proc near               ; CODE XREF: _main+3Ap
.text:004010A0
.text:004010A0     l_mem           = dword ptr -4
.text:004010A0     arg_0           = dword ptr  8
.text:004010A0
.text:004010A0 000                 push    ebp
.text:004010A1 004                 mov     ebp, esp
.text:004010A3 004                 push    ecx
.text:004010A4 008                 mov     [ebp+l_mem], ecx
.text:004010A7 008                 cmp     [ebp+arg_0], 0
.text:004010AB 008                 jz      short if_zero
.text:004010AD 008                 mov     eax, [ebp+l_mem]
.text:004010B0 008                 mov     dword ptr [eax], offset init ; structure init contains offsets.
.text:004010B0                                             ; Let's imagine them as indicies;
.text:004010B0                                             ; int init[] = {0, 2};
.text:004010B0                                             ; this[0] = &init;
.text:004010B6 008                 mov     ecx, [ebp+l_mem]
.text:004010B9 008                 add     ecx, 8
.text:004010BC 008                 call    a_constructor   ; this[2] = a_vtbl;
.text:004010C1
.text:004010C1     if_zero:                                ; CODE XREF: c_constructor+Bj
.text:004010C1 008                 mov     ecx, [ebp+l_mem]
.text:004010C4 008                 mov     edx, [ecx]
.text:004010C6 008                 mov     eax, [edx+4]
.text:004010C9 008                 mov     ecx, [ebp+l_mem]
.text:004010CC 008                 mov     dword ptr [ecx+eax], offset c_vtbl ; this[init[1]] = c_vtbl;
.text:004010D3 008                 mov     edx, [ebp+l_mem]
.text:004010D6 008                 mov     eax, [edx]
.text:004010D8 008                 mov     ecx, [eax+4]
.text:004010DB 008                 sub     ecx, 8
.text:004010DE 008                 mov     edx, [ebp+l_mem]
.text:004010E1 008                 mov     eax, [edx]
.text:004010E3 008                 mov     edx, [eax+4]
.text:004010E6 008                 mov     eax, [ebp+l_mem]
.text:004010E9 008                 mov     [eax+edx-4], ecx ; this[init[1] - 1] = init[1] - 2;
.text:004010ED 008                 push    offset aCConstructor ; "c::constructor"
.text:004010F2 00C                 call    _printf
.text:004010F7 00C                 add     esp, 4
.text:004010FA 008                 mov     eax, [ebp+l_mem]
.text:004010FD 008                 mov     esp, ebp
.text:004010FF 004                 pop     ebp
.text:00401100 000                 retn    4
.text:00401100     c_constructor   endp

main
.text:00401000     _main           proc near               ; CODE XREF: start+16Ep
.text:00401000
.text:00401000     i               = dword ptr -20h
.text:00401000     var_1C          = dword ptr -1Ch
.text:00401000     l_mem           = dword ptr -18h
.text:00401000     var_14          = dword ptr -14h
.text:00401000     var_10          = dword ptr -10h
.text:00401000     var_C           = dword ptr -0Ch
.text:00401000     var_4           = dword ptr -4
.text:00401000
.text:00401000 000                 push    ebp
.text:00401001 004                 mov     ebp, esp
..............................
.text:0040101D 028                 call    operator new(uint)
.text:00401022 028                 add     esp, 4
.text:00401025 024                 mov     [ebp+l_mem], eax
.text:00401028 024                 mov     [ebp+var_4], 0
.text:0040102F 024                 cmp     [ebp+l_mem], 0
.text:00401033 024                 jz      short if_fail   ; i = 0;
.text:00401035 024                 push    1
.text:00401037 028                 mov     ecx, [ebp+l_mem]
.text:0040103A 028                 call    c_constructor
.text:0040103F 024                 mov     [ebp+i], eax    ; i = new c();
.text:00401042 024                 jmp     short proceed
.text:00401044     ; ---------------------------------------------------------------------------
.text:00401044
.text:00401044     if_fail:                                ; CODE XREF: _main+33j
.text:00401044 024                 mov     [ebp+i], 0      ; i = 0;
.text:0040104B
.text:0040104B     proceed:                                ; CODE XREF: _main+42j
.text:0040104B 024                 mov     eax, [ebp+i]
.text:0040104E 024                 mov     [ebp+var_14], eax
.text:00401051 024                 mov     [ebp+var_4], 0FFFFFFFFh
.text:00401058 024                 mov     ecx, [ebp+var_14]
.text:0040105B 024                 mov     [ebp+var_10], ecx
.text:0040105E 024                 mov     edx, [ebp+var_10]
.text:00401061 024                 mov     eax, [edx]
.text:00401063 024                 mov     ecx, [eax+4]
.text:00401066 024                 mov     edx, [ebp+var_10]
.text:00401069 024                 mov     eax, [edx]
.text:0040106B 024                 mov     edx, [ebp+var_10]
.text:0040106E 024                 add     edx, [eax+4]
.text:00401071 024                 mov     eax, [ebp+var_10]
.text:00401074 024                 mov     eax, [eax+ecx]
.text:00401077 024                 mov     ecx, edx        
.text:00401079 024                 call    dword ptr [eax] ; call dword ptr [this[init[1]]]; //  i->fn();
................................................................
.text:00401099 024                 mov     esp, ebp
.text:0040109B 004                 pop     ebp
.text:0040109C 000                 retn
.text:0040109C     _main           endp

Невиртуальная ф-я класса с
.text:00401160     c_fn            proc near               ; DATA XREF: .rdata:c_vtblo
.text:00401160
.text:00401160     var_4           = dword ptr -4
.text:00401160
.text:00401160 000                 sub     ecx, [ecx-4]
.text:00401163 000                 jmp     loc_401170
.text:00401163     ; ---------------------------------------------------------------------------
.text:00401168 000                 align 10h
.text:00401170
.text:00401170     loc_401170:                             ; CODE XREF: c_fn+3j
.text:00401170 000                 push    ebp
.text:00401171 004                 mov     ebp, esp
.text:00401173 004                 push    ecx
.text:00401174 008                 mov     [ebp+var_4], ecx
.text:00401177 008                 push    offset aCFn     ; "c::fn"
.text:0040117C 00C                 call    _printf
.text:00401181 00C                 add     esp, 4
.text:00401184 008                 mov     esp, ebp
.text:00401186 000                 pop     ebp
.text:00401187 -04                 retn
.text:00401187     c_fn            endp ; sp =  4

Виртуальные таблицы и таблица индексов
.rdata:0040811C     c_vtbl          dd offset c_fn          ; DATA XREF: c_constructor+2Co
.rdata:00408120     init            dd 0                    ; DATA XREF: c_constructor+10o
.rdata:00408124                     dd 8
.rdata:00408138     a_vtbl          dd offset a_fn          ; DATA XREF: a_constructor+Ao

Вкратце, происходит следующее:
Внутри конструктора класса с видим, что он в самое начало вирт. таблицы записывает некую таблицу индексов, которой потом пользуется для инициализации и позднее поиска виртуальных таблиц и ф-й в них. Мои комментарии справа подразумевают, что в таблице смещения не в байтах, а в DWORD'ах, т.е. индексы.
Далее происходит вызов конструктора класса а, который записывает во 2-й элемент таблицы адрес вирт. таблицы класса а. После этого происходит замещение этого адреса адресом вирт. таблицы класса с, которая вмещает в себя невиртуальную ф-ю в классе с. После выполняется все остальное тело конструктора.
В main можно увидеть, как вызов i->fn(); происходит косвенно через регистр еах.
P.S.: Спасибо за вопрос. Это заинтересовало меня, поскольку в VS 2003 .NET сишный компилер генерит несколько иной код. В частности меня заинтересовал единственный параметр в конструкторе класса с равный 1. В конструкторе же можно видеть, что ежели этот параметр равен нулю, то вызова конструктора базового класса не произойдет. Пока я не знаю к какой опере это относится и как можно добится того, чтоб конструктор предка не вызывался вовсе. Кроме того, при обычном наследовании(невиртуальном) у конструктора отсутствует этот параметр вообще. Так что это повод провести более полный анализ.
Thx!!!
... locked in silent monolog ...
Re[13]: Вызов виртуального метода для класса
От: elcste  
Дата: 22.10.04 02:22
Оценка: +1
Здравствуйте, erithion aka tyomik, Вы писали:

EAT>>>Забыл упомянуть, что вызов невиртуальных методов всегда происходит непосредственно, по адресу, за исключением сложных случаев наследования, когда невиртуальный метод таки попадает в виртуальную таблицу и вызывается косвенно.

EAT>class a
EAT>{
EAT>public:
EAT>    a()
EAT>    {
EAT>        printf("a::constructor");
EAT>    }
EAT>    virtual void fn()
EAT>    {
EAT>        printf("a::fn");
EAT>    }
EAT>};
EAT>class c: public virtual a
EAT>{
EAT>public:
EAT>    c()
EAT>    {
EAT>        printf("c::constructor");
EAT>    }
EAT>    void fn()
EAT>    {
EAT>        printf("c::fn");
EAT>    }
EAT>};

c::fn — виртуальная функция.

EAT>P.S.: Спасибо за вопрос. Это заинтересовало меня, поскольку в VS 2003 .NET сишный компилер генерит несколько иной код. В частности меня заинтересовал единственный параметр в конструкторе класса с равный 1. В конструкторе же можно видеть, что ежели этот параметр равен нулю, то вызова конструктора базового класса не произойдет. Пока я не знаю к какой опере это относится и как можно добится того, чтоб конструктор предка не вызывался вовсе. Кроме того, при обычном наследовании(невиртуальном) у конструктора отсутствует этот параметр вообще. Так что это повод провести более полный анализ.


Виртуальные базовые классы инициализируются только из конструктора most derived class.


P.S. Учите язык.
Re[13]: Вызов виртуального метода для класса
От: Chez Россия  
Дата: 22.10.04 09:10
Оценка:
EAT>P.S.: Спасибо за вопрос.
Всегда пожалуйста
Chez, ICQ# 161095094
Re[14]: Вызов виртуального метода для класса
От: erithion aka tyomik  
Дата: 22.10.04 12:36
Оценка:
Здравствуйте, elcste, Вы писали:

E>Здравствуйте, erithion aka tyomik, Вы писали:

E>c::fn — виртуальная функция.

Еще раз повторюсь, меня не интересуют стандарты, несмотря на то, что я тоже читал Страуструпа и другую не менее интересную литературу и тоже прекрасно помню, что всеми ими такой метод класса обзывается виртуальным.
С точки же зрения исследователя, я знаю другое, а именно, что это чистый метод класса в реализации МС С++ компилятора. Его виртуальность возникает вследствие перекрытия имен, которая разрешается в пользу виртуальности метода наследника. И виртуальность его косвенная, поскольку реализуется через переходник. На что собсно код и указывает. В виртуальной таблице класса с не адрес самой процедуры, а адрес так называемого переходника на процедуру(метод класса c::fn) с коррекцией указателя перед переходом. Обрати внимание еще раз, мож теперь понятнее буит:

.text:00401160     c_thunk_fn      proc near               ; DATA XREF: .rdata:c_vtblo
.text:00401160
.text:00401160     var_4           = dword ptr -4
.text:00401160
.text:00401160 000                 sub     ecx, [ecx-4]
.text:00401163 000                 jmp     c_fn
.text:00401163     c_thunk_fn      endp
.text:00401170     -----------------------------------------------------------------------
.text:00401170     c_fn            proc near               ; CODE XREF: c_thunk_fn+3j
.text:00401170
.text:00401170     var_4           = dword ptr -4
.text:00401170
.text:00401170 000                 push    ebp
.text:00401171 004                 mov     ebp, esp
.text:00401173 004                 push    ecx
.text:00401174 008                 mov     [ebp+var_4], ecx
.text:00401177 008                 push    offset aCFn     ; "c::fn"
.text:0040117C 00C                 call    _printf
.text:00401181 00C                 add     esp, 4
.text:00401184 008                 mov     esp, ebp
.text:00401186 004                 pop     ebp
.text:00401187 000                 retn
.text:00401187     c_fn            endp

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

E>Виртуальные базовые классы инициализируются только из конструктора most derived class.

Я сказал про параметр, вследствие равенства нулю которого вызова конструктора базового класса вообще не происходит. Как бы я не наследовался, вызов все равно будет, т.е. если присутствует один параметр в конструктор, то пока что у меня он всегда был равен 1. Равенства же его 0 я пока не смог добиться. И пока не упомню ситуаций, когда такое возможно. Разве что для нужд компилятора в специфических ситуациях, когда тока так можно выйти из положения.


E>P.S. Учите язык.

Спасибо! Торжественно обещаю
А какой? Алгол?
Я слышал множество пунктов стандарта и предложений по реализации взято именно оттуда.
... locked in silent monolog ...
Re[15]: Вызов виртуального метода для класса
От: elcste  
Дата: 23.10.04 03:58
Оценка: :)
Здравствуйте, erithion aka tyomik, Вы писали:

E>>c::fn — виртуальная функция.


EAT>Еще раз повторюсь, меня не интересуют стандарты, несмотря на то, что я тоже читал Страуструпа и другую не менее интересную литературу и тоже прекрасно помню, что всеми ими такой метод класса обзывается виртуальным.


То есть эту функцию невиртуальной называете только Вы. Или еще кто-то?

EAT>С точки же зрения исследователя, я знаю другое, а именно, что это чистый метод класса в реализации МС С++ компилятора.


Вот только меня, в свою очередь, совершенно не интересует "реализация МС С++ компилятора". В данный момент я работаю с процессором Blackfin (ADSP-BF561), и мне интересен код, который генерирует VisualDSP++ от Analog Devices. Не хотите исследовать его для разнообразия?

    .file ".\test.cpp";

    .section program;

.epctext:

    .align 2;
_fn__1aFv:
// ".\test.cpp" line 12 col 18
        link  12;
// ".\test.cpp" line 14 col 9
//         -- 3 bubbles --
        R0.L = .epcrodata+16;
        R0.H = .epcrodata+16;
        CALL.X _printf;
        P0=[FP+ 4];
        unlink;
//         -- 3 bubbles --
        JUMP (P0);

._fn__1aFv.end:
    .type _fn__1aFv,STT_FUNC;

    .align 2;
_main:
// ".\test.cpp" line 31 col 5
        [--SP]=RETS;
        [--SP]=FP;
        FP = SP ;
        [--SP]=(P5:4);
//         -- 3 bubbles --
        SP +=  -12;
        CALL.X ___mark_dtor;
// ".\test.cpp" line 33 col 8
        R0 =   12;
        CALL.X ___nw__FUl;
        P5 = R0 ;
        CC =  R0 ==  0;
        P4 =   0;
        IF CC JUMP  ._P2L2 ;
// ".\test.cpp" line 10 col 9
        R0.L = .epcrodata;
        R0.H = .epcrodata;
// ".\test.cpp" line 33 col 8
        P4 = P5 ;
        R1.L = ___vtbl__1a;
        R1.H = ___vtbl__1a;
        P4 +=  8;
        [P5+ 4] = P4;
        [P5+ 8] = R1;
// ".\test.cpp" line 10 col 9
        CALL.X _printf;
        R0.L = ___vtbl__1c;
        R0.H = ___vtbl__1c;
        P0.L = .epcdata;
        P0.H = .epcdata;
        [P5+ 0] = R0;
        P0=[P0+ 4];
// ".\test.cpp" line 23 col 9
        R0.L = .epcrodata+24;
        R0.H = .epcrodata+24;
// ".\test.cpp" line 10 col 9
//         -- 2 bubbles --
        [P4+ 0] = P0;
// ".\test.cpp" line 23 col 9
        CALL.X _printf;
        P4 = P5 ;

._P2L2:
// ".\test.cpp" line 34 col 5
        P1=[P4+ 0];
//         -- 4 bubbles --
        R0=W[P1+ 8] (X);
        P0 = R0 ;
        P1=[P1+ 12];
//         -- 3 bubbles --
        P0 = P4 + P0;
        R0 = P0 ;
        CALL (P1);
// ".\test.cpp" line 35 col 5
        R0 = P4 ;
        CALL.X ___dl__FPv;
        SP +=  12;
        (P5:4)=[SP++];
// ".\test.cpp" line 36 col 5
//         -- 3 bubbles --
        R0 =   0;
        P2=[SP+ 4];
        FP=[SP+ 0];
        SP +=  8;
//         -- 2 bubbles --
        JUMP (P2);

._main.end:
    .global _main;
    .type _main,STT_FUNC;

    .align 2;
_fn__1cFv:
// ".\test.cpp" line 25 col 10
        link  12;
// ".\test.cpp" line 27 col 9
//         -- 3 bubbles --
        R0.L = .epcrodata+40;
        R0.H = .epcrodata+40;
        CALL.X _printf;
        P0=[FP+ 4];
        unlink;
//         -- 3 bubbles --
        JUMP (P0);

._fn__1cFv.end:
    .type _fn__1cFv,STT_FUNC;

.epctext.end:

    .extern _printf;
    .type _printf,STT_FUNC;
    .extern ___mark_dtor;
    .type ___mark_dtor,STT_FUNC;
    .extern ___nw__FUl;
    .type ___nw__FUl,STT_FUNC;
    .extern ___dl__FPv;
    .type ___dl__FPv,STT_FUNC;

    .section data1;

    .align 8;
.epcdata:
    .type .epcdata,STT_OBJECT;
.epc.cplus.compiled:
    .type .epc.cplus.compiled,STT_OBJECT;
    .byte = 0x00,0x00,0x00,0x00;
    .byte4 = ___vtbl__1a__1c;
.epcdata.end:

    .section constdata;

    .align 8;
.epcrodata:
    .type .epcrodata,STT_OBJECT;
    .byte = 0x61,0x3A,0x3A,0x63,0x6F,0x6E,0x73,0x74,0x72,0x75,0x63,0x74;
    .byte = 0x6F,0x72,0x00,0x00,0x61,0x3A,0x3A,0x66,0x6E,0x00,0x00,0x00;
    .byte = 0x63,0x3A,0x3A,0x63,0x6F,0x6E,0x73,0x74,0x72,0x75,0x63,0x74;
    .byte = 0x6F,0x72,0x00,0x00,0x63,0x3A,0x3A,0x66,0x6E,0x00;
.epcrodata.end:
    .align 4;
___vtbl__1a:
    .type ___vtbl__1a,STT_OBJECT;
    .byte = 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00;
    .byte4 = _fn__1aFv;
.___vtbl__1a.end:
    .align 4;
___vtbl__1c:
    .type ___vtbl__1c,STT_OBJECT;
    .byte = 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00;
    .byte4 = _fn__1cFv;
.___vtbl__1c.end:
    .align 4;
___vtbl__1a__1c:
    .type ___vtbl__1a__1c,STT_OBJECT;
    .byte = 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF,0x00,0x00;
    .byte4 = _fn__1cFv;
.___vtbl__1a__1c.end:

    .section data1;

Обратите внимание на то, что вызов виртуальной функции c::fn происходит косвенно, через таблицу виртуальных функций, несмотря на совпадение в данном случае статического и динамического типов указуемого i объекта.

EAT>Его виртуальность возникает вследствие перекрытия имен, которая разрешается в пользу виртуальности метода наследника.


Bravo! You made my day!

E>>Виртуальные базовые классы инициализируются только из конструктора most derived class.

EAT>Я сказал про параметр, вследствие равенства нулю которого вызова конструктора базового класса вообще не происходит.

Прочитав учебник, Вы осознаете смысл сказанного выше. Если же Вы принципиально не читаете ничего, кроме ассемблерных листингов, помедитируйте над результатом трансляции следующего примера.

#include <iomanip>
#include <iostream>

struct foo
{
    bool qux;
    foo() : qux(true) {}
    foo(bool qux) : qux(qux) {}
};

struct bar : virtual foo
{
    bar() : foo(false) {}
};

struct baz : bar {};

int main()
{
    if(baz().qux)
        std::cout << "Surprise!" << std::endl;
}

E>>P.S. Учите язык.
EAT>Спасибо! Торжественно обещаю
EAT>А какой? Алгол?

Нет, русский.
Re[16]: Вызов виртуального метода для класса
От: erithion aka tyomik  
Дата: 24.10.04 19:39
Оценка:
Здравствуйте, elcste, Вы писали:

E>То есть эту функцию невиртуальной называете только Вы. Или еще кто-то?

Я б сказал, что для меня(и не только) она таковой не является именно потому, что стандартный подход реверсирования в этом случае несколько изменяется. Именно изза наличия переходника.

E>Вот только меня, в свою очередь, совершенно не интересует "реализация МС С++ компилятора". В данный момент я работаю с процессором Blackfin (ADSP-BF561), и мне интересен код, который генерирует VisualDSP++ от Analog Devices. Не хотите исследовать его для разнообразия?

Нет, спасибо, пока не хочу.Поскольку меня ждет не менее интересная работа с кодом ARM-процессора и тонкостями его построения компилятором.
Но раз уж речь зашла об этом, то компилер С++ для ARM'а вообще не признает виртуальное наследование. А вызов виртуальных методов производит непосредственно или же с jump'ом на код коррекции адреса перехода.
Так что не думаю что стоило здесь приводить подобные листинги, поскольку разговор шел о МС С++ в частности, и в целом для х86, если не ошибаюсь.

EAT>>Его виртуальность возникает вследствие перекрытия имен, которая разрешается в пользу виртуальности метода наследника.


E>Bravo! You made my day!

Я рад что тебе понравилось. Зови в следующий раз, посмешу

E>>>Виртуальные базовые классы инициализируются только из конструктора most derived class.

EAT>>Я сказал про параметр, вследствие равенства нулю которого вызова конструктора базового класса вообще не происходит.

E>Прочитав учебник, Вы осознаете смысл сказанного выше. Если же Вы принципиально не читаете ничего, кроме ассемблерных листингов, помедитируйте над результатом трансляции следующего примера.


За это спасибо. Это как раз то, что мне было нужно. Ответ прозвучал и раньше, но боюсь я его не сразу понял.
Так что иду к стандартам по виртуальному наследованию и не только
... locked in silent monolog ...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.