Виртуальные функции разных классов имеют одинаковый (недействительный?) Адрес памяти - PullRequest
1 голос
/ 10 июня 2019

Рассмотрим следующий фрагмент:

#include<cstdio>
#include<iostream>
using namespace std;
class Class1{
    public:
    virtual void print(){
        cout << "Class1"<<endl;
        printf("%p\n", &Class1::print);
    }
};
class Class2{
    public:
    virtual void print(){
        cout << "Class2"<<endl;
        printf("%p\n", &Class2::print);
    }
};
class Class3{
    public:
    virtual void print(){
        cout << "Class3"<<endl;
        printf("%p\n", &Class3::print);
    }
};
int main(){
    Class1 c1;
    Class2 c2;
    Class3 c3;
    c1.print();
    c2.print();
    c3.print();
}

Я скомпилировал следующий код на g ++ (MinGW) 8.2.0 и запустил вывод для cmd и Powershell. (Я не уверен, имеет ли это значение вообще.) Я ожидал, что три напечатанных адреса будут разными. Однако три напечатанных адреса одинаковы, в моем случае «00000001», что тоже кажется странным, потому что это не похоже на действительный адрес (не кратный 4)

  • Это происходит только при использовании ключевого слова "virtual".
  • Независимо от того, наследует ли Class2 от Class1, не имеет значения. (То же самое с 2-3, 1-3 и т. Д.)

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

Я изучил другие вопросы, такие как: this , в котором функция fork () была в центре вопроса; это .. и, посмотрев на все эти вопросы, спрашивающие об «одном и том же адресе», я подумал: может быть, это как-то связано с ОС? Но после этого я не смог найти ничего подходящего.


TL; DR:

1. Приведенный выше код печатает три одинаковых адреса. Зачем? Как это возможно?

2. Напечатанный адрес выглядит недействительным (00000001). Почему это?

1 Ответ

3 голосов
/ 10 июня 2019

Ваш код имеет неопределенное поведение.&Class3::print - указатель на функцию-член, но %p ожидает void *.Если вы приведете указатель к void *, то получите действительные результаты.

#include<cstdio>
#include<iostream>
using namespace std;
class Class1{
    public:
    virtual void print(){
        cout << "Class1"<<endl;
        printf("%p\n", (void*)&Class1::print);
    }
};
class Class2{
    public:
    virtual void print(){
        cout << "Class2"<<endl;
        printf("%p\n", (void*)&Class2::print);
    }
};
class Class3{
    public:
    virtual void print(){
        cout << "Class3"<<endl;
        printf("%p\n", (void*)&Class3::print);
    }
};
int main(){
    Class1 c1;
    Class2 c2;
    Class3 c3;
    c1.print();
    c2.print();
    c3.print();
}

output

Class1
0x400b50
Class2
0x400be0
Class3
0x400c70
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...