オブジェクトのスライスについて難しい方法を学んでいます。ポインタがオブジェクトのスライスになる可能性があるかどうか疑問に思っています。言い換えると:
- ポインターがオブジェクト スライスの犠牲になることはありますか? または、ポインターを使用している限り、オブジェクト スライスから常に安全ですか?
オブジェクトのスライスについて難しい方法を学んでいます。ポインタがオブジェクトのスライスになる可能性があるかどうか疑問に思っています。言い換えると:
それは、「スライス」をどれだけ大まかに定義するかによって異なります。ある意味では、ベース ポインター (または参照) で派生オブジェクトを指すと、非仮想関数はすべてスライスされます。例えば:
class A {
void Print() { cout << "Class A\n"; }
};
class B : public A {
void DoB() {}
void Print() { cout << "Class B\n"; }
};
B b;
A* a = &b;
a->DoB(); // Won't compile!
a->Print(); // Prints "Class A", not "Class B"
DoB
へのポインターを使用しているため、への呼び出しは機能しませんA
。そのため、コンパイラーはDoB
そのポインターで呼び出すことができることを知りません。このように、 の一部を失っているB
ので、これは一種のスライスと考えることができます。
特に最後の行は「名前隠蔽」と呼ばれる現象の一例です。は基底クラスでPrint
宣言されておらず、ポインタの型は であるため、コンパイラはの代わりに呼び出す必要があることを知りません。virtual
A
B::Print
A::Print
この問題の重要な例は、デストラクタで発生します。
class A {
~A() {}
};
class B : public A {
std::vector<int> v;
};
A* a = new B;
delete a; // What happens to B::v? Undefined behaviour!
ここでは、デストラクタが としてマークされていないためvirtual
、非仮想コンテキストで基底クラスのデストラクタを呼び出しました。つまり、B
のデストラクタは呼び出されません。
はい -base
から派生した任意の型のオブジェクトを参照しbase
、派生オブジェクトの正しい型を保持できるようにするには、へのポインターが必要です (そして、その価値については、参照でも同じことが言えます)。