42

pos座標xとyを格納する(位置から)というtypedef構造体を作成したいと思います。この構造体のいくつかの演算子をオーバーロードしようとしていますが、コンパイルされません。

typedef struct {
    int x;
    int y;

    inline pos operator=(pos a) {
        x=a.x;
        y=a.y;
        return a;
    }

    inline pos operator+(pos a) {
        return {a.x+x,a.y+y};
    }

    inline bool operator==(pos a) {
       if (a.x==x && a.y== y)
          return true;
       else
          return false;
    }
} pos;

私もこれの違いを知りたいと思いました:

inline bool operator==(pos a) {
    if(a.x==x && a.y== y)
       return true;
      else
       return false;
}

この:

bool operator==(pos a) const {
      if(a.x==x && a.y== y)
         return true;
      else
         return false;
}
4

4 に答える 4

94

あなたの宣言とそのメンバーの内訳はやや散らかっています:

を削除しますtypedef

typedefどちらも必須ではなく、C++のクラス/構造体宣言には望ましくありません。あなたのメンバーは、posあなたの現在のコンパイルの失敗の核となる、書かれたままの宣言についての知識を持っていません。

これを変える:

typedef struct {....} pos;

これに:

struct pos { ... };

無関係なインラインを削除する

クラス定義自体の中でメンバー演算子を宣言および定義しています。inline実装が現在の場所(クラス定義)に残っている限り、キーワードは必要ありません。


*this必要に応じてへの参照を返す

これは、実装内の豊富なコピー構造に関連しており、そうする強い理由がない限り実行すべきではありません。これは、次の表現イデオロギーに関連しています。

a = b = c;

これはに割り当てcられb、結果の値bはに割り当てられaます。これは、あなたが考えるかもしれないことに反して、次のコードと同等ではありません:

a = c;
b = c;

したがって、代入演算子は次のように実装する必要があります。

pos& operator =(const pos& a)
{
    x = a.x;
    y = a.y;
    return *this;
}

ここでも、これは必要ありません。デフォルトのコピー代入演算子は、上記を無料で実行します(そしてコード!woot!)

:コピー/スワップのイディオムを優先して、上記を回避する必要がある場合があり。この特定のケースでは必要ありませんが、次のようになります。

pos& operator=(pos a) // by-value param invokes class copy-ctor
{
    this->swap(a);
    return *this;
}

次に、スワップメソッドが実装されます。

void pos::swap(pos& obj)
{
    // TODO: swap object guts with obj
}

これを行うには、クラスcopy-ctorを使用してコピーを作成してから、例外安全スワッピングを使用して交換を実行します。その結果、受信したコピーはオブジェクトの古い内臓を離れ(そして破壊し)、オブジェクトはそこの所有権を引き継ぎます。コピー/スワップのイディオムの詳細と、その中の長所と短所をここで読んでください。


必要に応じて、const参照によってオブジェクトを渡します

すべてのメンバーへのすべての入力パラメーターは、現在、呼び出し時に渡されているものすべてのコピーを作成しています。このようなコードでは些細なことかもしれませんが、より大きなオブジェクトタイプでは非常にコストがかかる可能性があります。ここに例を示します。

これを変える:

bool operator==(pos a) const{
    if(a.x==x && a.y== y)return true;
    else return false;
}

これに:(これも簡略化されています)

bool operator==(const pos& a) const
{
    return (x == a.x && y == a.y);
}

何もコピーされないため、コードがより効率的になります。


最後に、あなたの質問に答える際に、として宣言されたメンバー関数または演算子とそうでないものの違いは何constですか?

メンバーは、そのconstメンバーを呼び出すと、基になるオブジェクトが変更されないことを宣言します(可変宣言は耐えられません)。オブジェクト、または参照とポインターconstに対して呼び出すことができるのは、メンバー関数のみです。たとえば、はローカルオブジェクトを変更しないため、として宣言する必要があります。ローカルオブジェクトを明確に変更するため、演算子はである必要はありませconstconstoperator +()constoperator =()const


概要

struct pos
{
    int x;
    int y;

    // default + parameterized constructor
    pos(int x=0, int y=0) 
        : x(x), y(y)
    {
    }

    // assignment operator modifies object, therefore non-const
    pos& operator=(const pos& a)
    {
        x=a.x;
        y=a.y;
        return *this;
    }

    // addop. doesn't modify object. therefore const.
    pos operator+(const pos& a) const
    {
        return pos(a.x+x, a.y+y);
    }

    // equality comparison. doesn't modify object. therefore const.
    bool operator==(const pos& a) const
    {
        return (x == a.x && y == a.y);
    }
};

EDIT OPは、代入演算子チェーンがどのように機能するかを確認したいと考えていました。以下は、これがどのように行われるかを示しています。

a = b = c;

これと同等です:

b = c;
a = b;

そして、これは必ずしもこれと同じではありません:

a = c;
b = c;

サンプルコード

#include <iostream>
#include <string>
using namespace std;

struct obj
{
    std::string name;
    int value;

    obj(const std::string& name, int value)
        : name(name), value(value)
    {
    }

    obj& operator =(const obj& o)
    {
        cout << name << " = " << o.name << endl;
        value = (o.value+1); // note: our value is one more than the rhs.
        return *this;
    }    
};

int main(int argc, char *argv[])
{

    obj a("a", 1), b("b", 2), c("c", 3);

    a = b = c;
    cout << "a.value = " << a.value << endl;
    cout << "b.value = " << b.value << endl;
    cout << "c.value = " << c.value << endl;

    a = c;
    b = c;
    cout << "a.value = " << a.value << endl;
    cout << "b.value = " << b.value << endl;
    cout << "c.value = " << c.value << endl;

    return 0;
}

出力

b = c
a = b
a.value = 5
b.value = 4
c.value = 3
a = c
b = c
a.value = 4
b.value = 4
c.value = 3
于 2012-12-26T23:24:13.687 に答える
6

あなたの代わりにtypedef struct { ... } pos;やるべきですstruct pos { ... };。ここでの問題は、pos定義される前に型名を使用していることです。名前を構造体定義の先頭に移動することにより、構造体定義自体の中でその名前を使用できます。

さらに、このtypedef struct { ... } name;パターンはC-ismであり、C++ではあまり使用されていません。

についての質問に答えるためinlineに、この場合は違いはありません。メソッドが構造体/クラス定義内で定義されている場合、それは暗黙的にインラインで宣言されます。を明示的に指定するinlineと、メソッドはすでにインラインで宣言されているため、コンパイラはそれを事実上無視します。

inline同じメソッドが複数のオブジェクトファイルで定義されている場合、メソッドはリンカーエラーをトリガーしません。リンカーは、それらがすべて同じ実装であると想定して、1つを除くすべてを単に無視します。これは、インラインメソッドでの動作の唯一の保証された変更です。現在、これらは、関数をインライン化するかどうかに関するコンパイラの決定に影響を与えません。これらは、すべての変換ユニットで関数の実装を利用できるようにすることを容易にします。これにより、コンパイラは、関数をインライン化するオプションが得られます。そうする。)

于 2012-12-26T22:46:13.047 に答える
4

これを試して:

struct Pos{
    int x;
    int y;

    inline Pos& operator=(const Pos& other){
        x=other.x;
        y=other.y;
        return *this;
    }

    inline Pos operator+(const Pos& other) const {
        Pos res {x+other.x,y+other.y};
        return res;
    }

    const inline bool operator==(const Pos& other) const {
        return (x==other.x and y == other.y);
    }
 };  
于 2012-12-26T23:01:30.373 に答える
3
  1. bool operator ==(pos a)const{-このメソッドはオブジェクトの要素を変更しません。
  2. bool operator ==(pos a){-オブジェクトの要素を変更する可能性があります。
于 2012-12-26T22:59:04.787 に答える