Polimorfizm

0
  1. Czy da się jakoś dostać do Vtable, albo Vptr?
  2. Sprawdzałem rozmiar pustej klasy metodą 'sizeof' i wynosi on 1 bajt, dlaczego nie 0? Po dodaniu funkcji wirtualnej wynik to 4, rozumiem, że to przez dodanie Vptr-a, ale jeśli pusta klasa ma 1 bajt to wskaźnik miałby 3 bajty(domyślam się, że klasa tak naprawdę nie ma rozmiaru)?
  3. Dziedziczenie po klasie wirtualnie np. class Derived : virtual public Base, stosuje się wyłącznie przy problemie diamentu, czy jest to bardziej zaawansowany mechanizm? Na czym polega jego działanie(link)?
  4. Poniższy kod się kompiluje i o dziwo działa poprawnie, czy jest to undefined behavior?
class Animal
{
public:
	Animal() = default;
	virtual ~Animal() = default;
};
//
class Cat : public Animal
{
public:
	Cat() = default;
	void speak() { std::cout << "Cat\n"; }
};
//
class Dog : public Animal
{
public:
	Dog() = default;
	void fly() { std::cout << "Fly\n"; }
};
//
int main()
{
	Animal* ptr = new Dog();
	reinterpret_cast<Cat*>(ptr)->speak();
}
5
leto napisał(a):
  1. Czy da się jakoś dostać do Vtable, albo Vptr?

To c++, więc da się ... jak wiesz gdzie szukać, to możesz skakać po pamięci ... tylko po co? To jest z tego co pamiętam, zdefiniowane przez ABI, które jest zastosowane.

  1. Sprawdzałem rozmiar pustej klasy metodą 'sizeof' i wynosi on 1 bajt, dlaczego nie 0? Po dodaniu funkcji wirtualnej wynik to 4, rozumiem, że to przez dodanie Vptr-a, ale jeśli pusta klasa ma 1 bajt to wskaźnik miałby 3 bajty(domyślam się, że klasa tak naprawdę nie ma rozmiaru)?

Ten 1 bajt został dodany sztucznie. Jak inaczej zaalokować pustą klasę i zapewnić arytmetyką wskaźnikową (czyli ta pusta klasa, z jakiegoś dziwnego powodu wsadzona do tablicy)?
Po dodaniu funkcji wirtualnych pojawił się vtable i vptr i nie było sensu dodawać bajta.

  1. Dziedziczenie po klasie wirtualnie np. class Derived : virtual public Base, stosuje się wyłącznie przy problemie diamentu, czy jest to bardziej zaawansowany mechanizm? Na czym polega jego działanie(link)?

Wspólne klasy bazowe nie są duplikowane. Najlepiej nie stosować jak nie trzeba ;)

  1. Poniższy kod się kompiluje i o dziwo działa poprawnie, czy jest to undefined behavior?

Tak. Bo klasa Cat mogłaby się odnosić do jakiś danych, których przecież w obiekcie typy Dog nie ma. Adres w pamięci takich danych zostanie obliczony względem klasy Dog, czyli czytasz/modyfikujesz nie wiadomo co.

2

Poniższy kod się kompiluje i o dziwo działa poprawnie, czy jest to undefined behavior?

Działa poprawnie gdyż funkcje którą wywołujesz kompilator traktuje tutaj jako statyczną. Nie jest wirtualna i nie ma dostępu do żadnych wewnętrznych zmiennych z klasy (przy pomocy operator this).
Oczywiście to w dalszym ciągu jest UB, gdyż nie ma żadnej gwarancji że w innej implementacji kompilator postąpi podobnie.
Konsekwencją tego jest możliwość skompilowania i uruchomienia poniższego kodu na tego rodzaju kompilatorach.

  Cat* ptr {nullptr};
  ptr->speak();
3

A propos reinterpret_cast<> polecam:

0 użytkowników online, w tym zalogowanych: 0, gości: 0