Почему тип класса меняется при использовании виртуальной функции?

#c

#c

Вопрос:

Я хотел бы знать, почему тип класса изменяется при использовании строки и виртуальной функции.

 #include <iostream>
#include <typeinfo>
 
class Base {
public:
    std::string str;
    virtual void vvfunc() {};
};
 
class Derived : public Base {
public:
    void vvfunc() {}
};
 
using namespace std;
int main() {
   Derived* pd = new Derived;
   Derived* pd2 = pd;
   cout<<amp;pd<<endl;
   cout<<amp;pd2<<endl;
   cout << typeid( pd ).name() << endl;
   cout << typeid( *pd ).name() << endl;
   cout << typeid( pd2 ).name() << endl;
   cout << typeid( *pd2 ).name() << endl;
   delete pd;
   cout << typeid( pd2 ).name() << endl;
   cout << typeid( *pd2 ).name() << endl;
}
 

вывод

 0x7ffeeaadd8f0
0x7ffeeaadd8d8
P7Derived
7Derived
P7Derived
7Derived
P7Derived
4Base
 

И когда я не использую «виртуальный», тогда я могу получить тот тип класса, который мне нужен.(или не используя строку в классе, что приводит к тому же результату)

 #include <iostream>
#include <typeinfo>

class Base {
public:
    std::string str;
    void vvfunc() {};
};

class Derived : public Base {
public:
    void vvfunc() {}
};

using namespace std;
int main() {
   Derived* pd = new Derived;
   Derived* pd2 = pd;
   cout<<amp;pd<<endl;
   cout<<amp;pd2<<endl;
   cout << typeid( pd ).name() << endl;
   cout << typeid( *pd ).name() << endl;
   cout << typeid( pd2 ).name() << endl;
   cout << typeid( *pd2 ).name() << endl;
   delete pd;
   cout << typeid( pd2 ).name() << endl;
   cout << typeid( *pd2 ).name() << endl;
}
 

вывод

 0x7ffeec60e790
0x7ffeec60e778
P7Derived
7Derived
P7Derived
7Derived
P7Derived
7Derived
 

Кто-нибудь может объяснить, почему это происходит?

Комментарии:

1. Поскольку pd2 имеет то же значение, pd что и , разыменование pd2 after delete pd; имеет неопределенное поведение.

2. Вы не можете разыменовывать указатель, если объект, на который он указывает, больше не существует. Вы понимаете, что оба pd pd2 указателя и указывают на один и тот же объект? Вы можете проверить, напечатав адрес этого объекта: amp;*pd и amp;*pd2 (теперь вы печатаете адреса самих указателей, которые отличаются).

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

4. Я использовал clang (Apple LLVM версии 10.0.1 (clang-1001.0.46.4)). Спасибо всем вам за ответ на мой вопрос. И я понимаю, что последующий код delete неверен, и у моего компилятора было неправильное поведение.