2011-11-13 16 views
0

Mark Allen Weissのデータ構造に関する本の中で、次のコードが出てきました。定数参照ラッパー

template <class Object> 
class Cref 
{ 
public: 
Cref () : obj (NULL) { } 
explicit Cref(const Object & x) : obj (&x) { 
const Object & get() const 
{ 
if (isNull()) 
    throw NullPointerException() ; 
else 
return *obj; 
} 
bool isNull() const 
(return obj == NULL; } 

private: 
const Object *obj; 
}; 

ここでのポイントは、定数参照をnull /初期化することです。しかし、私は以下を理解しているかどうかわかりません: 1.別の定数参照を使って定数参照を初期化します。しかし、なぜそれがobj(& x)として再び行われますか? constオブジェクト& xの&はobj(& x)の& xとは異なりますか?私はこれを見るが、それがなぜそうであるべきか明確ではない。 Plsは説明します。 2. getメソッド() - このクラスのprivateメンバーobjのconst参照を返そうとします。これはすでにconst参照です。 * objを返すのはなぜ?objだけではないのですか? 3.なぜ明示的なキーワードですか?暗黙の型変換が行われるとどうなりますか?誰かがこのためのシナリオを提供することはできますか?

おかげ

答えて

1
  1. 部材objObject*であるが、コンストラクタは参照を取ります。したがって、ポインタを取得するには、アドレス演算子の&を適用する必要があります。そして、メンバはNULL(デフォルトのコンストラクタで設定可能)であり、参照は決してNULLになる可能性があるため、ポインタです。

  2. プライベートメンバはconst参照ではありませんが、CONSTへpoinetr。参照を取得するために逆参照されます。

  3. この特定のケースでは、潜在的な暗黙の変換のいずれかの負の効果も見られません。

+0

説明をありがとう!特に#2! :) – svk

+0

#1についても、これは宣言の問題であることを意味します。実際にポインタに代入するときはconstオブジェクト& x;のようなconst参照しか宣言できないので、ptr =&xが実行されることは避けられません。私の理由は正しいのですか? – svk

+0

@SuprajaJayakumar:論理的な観点から、リファレンスは基本的にオブジェクトの名前を付けます。つまり、コンストラクタ内で渡されたオブジェクトには 'x'という名前が付いています(const参照であるためconstです)。したがって、 'x'はその型の変数を使うのとまったく同じです。変数へのポインタを得るには、addess-of演算子 '&'を使います。したがって、 'x'と同じことをします。リファレンスがシンボル '&'を使って定義されているという事実は、これと論理的には無関係です。そのためにキーワード 'ref'を使うことに決めたのであれば、同じだったでしょう。 – celtschk

1

1)obj(&x)における&xは、アドレスの演算子として使用されます。

2)いいえ、ポインタです。その時間はObject *であり、Object &ではありません。

3)独自の型キャスト演算子を持つ互換性のないポインタ型からのキャストを防止する。

C++は、利用可能なヌルの3つの味を持っています

  • NULL - 時代遅れ。ポインタを返すC関数の戻り値のチェックにのみ使用してください。
  • 0 - 非推奨です。リテラルゼロは、標準でヌルポインタになるように定義されています。
  • nullptr - これはnullをテストするための好ましい方法です。さらに、nullptr_tは型安全なnullです。
0

1)トークン&は、3つの意味を有する:

  • 単項アドレス演算子:そのオブジェクトへのポインタを与える、任意の左辺式のアドレスを取ります。
  • 参照sigil:宣言では、参照型を意味します。
  • バイナリビット単位のAND演算子 - だから、それはあなたが、宣言や式を見ているかどうかを知っておくことが重要ですここ

使用されません。

explicit Cref(const Object & x) 

ここシギルパラメータxのタイプはconstあるObjectへの参照である意味、関数パラメータの宣言に現れます。

: obj (&x) {} 

ここで、演算子はメンバー初期化式で使用されます。メンバobjは、xへのポインタに初期化されています。

2)メンバobjは実際にはポインタなので、参照を取得するには参照解除演算子unary *が必要です。

3)一般的に、1つの引数をとることができる(コピーではない)コンストラクタにはexplicitを使用することをお勧めします。言語が明示的にデフォルトになっておらず、意味するときに何らかの「暗黙の」キーワードを使用するのは残念です。この場合は、ここではコンストラクタが暗黙的だった場合に発生する可能性が1つのではなく、悪いことだ:

Object create_obj(); 
void setup_ref(Cref& ref) { 
    ref = create_obj(); 
} 

ないコンパイラエラーまたは警告が、時間によって無効である一時的なオブジェクトにそのsetup_ref関数ポインタ店関数が戻ります!

0

1)objの型は参照ではなく、objはポインタであり、constポインタはアドレスで初期化する必要があるため、アドレス演算子&を適用する必要があります。 2)get()メソッドが返す参照は、クラスメンバーobjへの参照ではなく、objが指すオブジェクトへの参照であるため、*を使用してそれを参照する必要があります。 3)キーワードexplicitは、暗黙的な変換を拒否することを意味します。つまり、コンパイラに指示します。このコンストラクタで暗黙の変換を行わないでください。
例:

class Cref<Object> A;
Object B;
A=B;

これは、明示的に使われていないOKです - 私たちは右側にCrefのオブジェクトを必要とするので、コンパイラは、コンストラクタCrefを(constオブジェクト& B)とCrefのオブジェクトを作成する自動化します。しかし、明示的に追加すると、コンパイラは変換を行わず、コンパイルエラーが発生します。