アップキャスト ポインタ参照
-
21-09-2019 - |
質問
次のような人為的な例があります (実際のコードからのものです)。
template <class T>
class Base {
public:
Base(int a):x(a) {}
Base(Base<T> * &other) { }
virtual ~Base() {}
private:
int x;
};
template <class T>
class Derived:public Base<T>{
public:
Derived(int x):Base<T>(x) {}
Derived(Derived<T>* &other): Base<T>(other) {}
};
int main() {
Derived<int> *x=new Derived<int>(1);
Derived<int> y(x);
}
これをコンパイルしようとすると、次のようになります。
1X.cc: In constructor ‘Derived<T>::Derived(Derived<T>*&) [with T = int]’:
1X.cc:27: instantiated from here
1X.cc:20: error: invalid conversion from ‘Derived<int>*’ to ‘int’
1X.cc:20: error: initializing argument 1 of ‘Base<T>::Base(int) [with T = int]’
1) 明らかに、gcc はコンストラクターによって混乱されています。コンストラクターから参照を削除すると、コードがコンパイルされます。したがって、私の仮定は、ポインターの上級参照に何か問題が発生するということです。ここで何が起こっているのか誰か教えてもらえますか?
2) 少し関係のない質問です。コンストラクター(私と一緒に我慢する)の「他の削除」のような恐ろしいことをする場合、誰かが私にスタックの何かへのポインターを渡すとどうなりますか?
E.g. Derived<int> x(2);
Derived<int> y(x);
where
Derived(Derived<T>*& other) { delete other;}
ポインタがヒープ上の何かを正当に指していることを確認するにはどうすればよいでしょうか?
解決
Base<T>
はDerived<T>
の基本型であるが、Base<T>*
はDerived<T>*
の基本型ではありません。あなたはベースポインタの代わりに派生ポインタを渡すことができますが、ベースポインタ参照の代わりに派生ポインタ参照を渡すことはできません。
その理由は、あなたができたと仮定し、ということである、とベースのコンストラクタを想定参照に何らかの値を書き込むようにしてます:
Base(Base<T> * &other) {
Base<T> *thing = new Base<T>(12);
other = thing;
}
あなたはただDerived<T>
へのポインタへののないのDerived<T>
、何かへのポインタを書きました。コンパイラはこれを実現させないことができます。
他のヒント
- Derived へのポインターへの参照を Base へのポインターへの参照に変換することはできません。(テンプレートはここでの問題には関与しないため、以下の例からは削除されています。)
- ポインターの責任を延期したい場合は、スマート ポインター タイプを使用します。スマート ポインター タイプは、生のポインターでは表現できない「削除する責任」を表現できます。例には、std::auto_ptr および boost::shared_ptr, 、他にもたくさんあります。
ポインター参照をアップキャストできない理由:
struct Base {};
struct Derived : Base {};
struct Subclass : Base {};
int main() {
Derived d;
Derived* p = &d;
Derived*& d_ptr = p;
Base*& b_ptr = d_ptr; // this is not allowed, but let's say it is
Base b;
b_ptr = &b; // oops! d_ptr no longer points to a Derived!
Subclass s;
b_ptr = &s; // oops! d_ptr no longer points to a Derived!
}
「other」パラメータをBase ctorに渡すとき、次と同じことをしようとしています。 b_ptr = d_ptr
その上。
あなたのドキュメントでそれを書き込み、それを遵守するために、発信者に頼ることで、ヒープ上の何かへのポインタが指していることを確認します。誰でも自分のコンストラクタを呼び出すことは、スタックポインタを渡した場合は、すべてのベットはオフになっている、そしてそれはあなたのせいではありません - あなたは早期に問題をキャッチしようとすることができますが、無保証
。これはどのように標準ライブラリの作品だ - 。多くの場合、それは明らかなエラーをキャッチしますが、それはする必要はありませんだし、それは彼らが愚かな何もしていないことを確認するために、呼び出し側の責任です。
あなたのx
変数がポインタではありません、あなたがそれにnew Derived<int>
を割り当てる場合、それはする必要があります。
スタック上のものを削除すると、それをしません。あなたがスタックまたはヒープ(実際、C ++標準でも、スタックの存在を認めていない)に何かのアドレスを渡されているかどうかを指示する方法はありません。ここでの教訓は、あなたは、彼らがどこから来たのか伝える方法がない場合は特に、あなたが所有していないものを削除すべきではないということです。
わからない、なぜあなたは、ポインタへの参照をしたいです。なぜ
Base(Base<T> * other) { }
と
Derived(Derived<T>* other): Base<T>(other) {}
これは動作するはずです。
そして、答え他と同じように、私はあなたが合法的にポインタがヒープに指しているかどうかを知ることができるとは思わない。
編集
:例を考える:なぜ一つは、あなたがしようとしているものを行うことはできませんDerived1<int> *x = new Derived1<int>
Base<int> **xx =&x;
Derived2<int> y;
*xx = &y;
Derived1とDerived2は、基地から派生し、の異なるのクラスではどこ?あなたはそれが正当だと思いますか?今Derived2の種類Derived1 *ポイントのX?