仮想関数について
毎回、混乱するのでまとめ
何もなし
#include <iostream>
class Base {
public:
~Base() {
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base {
public:
~Derived() {
std::cout << "Derived destructor" << std::endl;
}
};
int main() {
Base *b = new Derived;
delete b;
return 0;
}
❯ clang++ -Wall -Wextra -Werror test.cpp && ./a.out
Base destructor
親クラスのデストラクタが呼ばれる
親クラスにvirtualあり
#include <iostream>
class Base {
public:
virtual ~Base() {
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base {
public:
~Derived() {
std::cout << "Derived destructor" << std::endl;
}
};
int main() {
Base *b = new Derived;
delete b;
return 0;
}
❯ clang++ -Wall -Wextra -Werror test.cpp && ./a.out
Derived destructor
Base destructor
両方にvirtual
#include <iostream>
class Base {
public:
virtual ~Base() {
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base {
public:
virtual ~Derived() {
std::cout << "Derived destructor" << std::endl;
}
};
int main() {
Base *b = new Derived;
delete b;
return 0;
}
❯ clang++ -Wall -Wextra -Werror test.cpp && ./a.out
Derived destructor
Base destructor
小クラスのみにvirtual
こんなの普通はしないけど
#include <iostream>
class Base {
public:
~Base() {
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base {
public:
virtual ~Derived() {
std::cout << "Derived destructor" << std::endl;
}
};
int main() {
Base *b = new Derived;
delete b;
return 0;
}
❯ clang++ -Wall -Wextra -Werror test.cpp && ./a.out
Base destructor
孫クラスありだと
当たり前ですね。
#include <iostream>
class Base {
public:
~Base() {
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base {
public:
virtual ~Derived() {
std::cout << "Derived destructor" << std::endl;
}
};
class Derived2 : public Derived {
public:
virtual ~Derived2() {
std::cout << "Derived2 destructor" << std::endl;
}
};
int main() {
Base *b = new Derived2;
delete b;
return 0;
}
❯ clang++ -Wall -Wextra -Werror test.cpp && ./a.out
Base destructor
まとめ(追記)
コメントに頂いたことを踏まえ自分でいろいろ試してみました。
アセンブリを見たり、sizeofでコンパイルされたクラスのサイズを比較したりすると、生成されるアセンブリは変更されるし、クラスのサイズ自体も増えるので、明確に使用されるとわかっているタイミングでしか、virtualをつけないほうがいいと結論しました。