3

私は次の不自然な例を持っています(実際のコードから来ています):

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;}

ポインタがヒープ上の何かを合法的に指していることを確認するにはどうすればよいですか?

4

5 に答える 5

3
  1. Derived へのポインターへの参照を Base へのポインターへの参照に変換することはできません。(テンプレートはここでは問題に寄与しないため、以下の例から削除します。)
  2. ポインターの責任を延期する場合は、スマート ポインター型を使用します。スマート ポインター型は、生のポインターでは表現できない "削除する責任" を表すことができます。例には、 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上記と同じことをしようとしています。

于 2009-12-22T21:16:19.953 に答える
2

ポインターがヒープ上の何かを指していることを確認するには、ドキュメントにそれを記述し、呼び出し元がそれに従うことを信頼します。コンストラクターを呼び出す人がスタック ポインターを渡した場合、すべての賭けはオフになり、それはあなたのせいではありません。問題を早期に発見しようとすることはできますが、保証はありません。

これが標準ライブラリの仕組みです。多くの場合、明らかなエラーをキャッチしますが、必須ではありません。呼び出し元が愚かなことをしていないことを確認する必要があります。

于 2009-12-22T21:08:06.727 に答える
0

ポインターへの参照が必要な理由がわかりません。なぜだめですか

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 はBase から派生した異なるクラスですか? 合法だと思いますか?Derived1* 型の x が Derived2 を指すようになったのでしょうか。

于 2009-12-22T21:15:24.353 に答える
0

変数はポインターではありませんx。変数に a を割り当てたい場合は、ポインターにする必要がありますnew Derived<int>

スタック上のものを削除することに関しては、それをしないでください。何かのアドレスが渡されたのがスタック上かヒープ上かを判断する方法はありません (実際、C++ 標準ではスタックの存在さえ認めていません)。ここでの教訓は、所有していないものを削除してはならないということです。特に、それらがどこから来たのかを知る方法がない場合はなおさらです。

于 2009-12-22T21:08:31.843 に答える