web-dev-qa-db-ja.com

typedef構造体の演算子のオーバーロード(C ++)

座標xとyを格納するpos(位置から)という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;
}
25
tuket

宣言とそのメンバーの内訳はいくぶん散らばっています。

typedefを削除します

typedefも必須ではなく、C++のクラス/構造体宣言には望ましくありません。メンバーは、pos as-writtenの宣言を認識していません。これは、現在のコンパイルの失敗の中核です。

これを変更:

_typedef struct {....} pos;
_

これに:

_struct pos { ... };
_

余分なインラインを削除する

クラス定義自体の中でメンバー演算子を定義の両方を定義しています。実装が現在の場所(クラス定義)に残っている限り、inlineキーワードは不要です。


必要に応じて_*this_への参照を返します

これは、実装内の豊富なコピー構成に関連しています。コピー構成は、そうするための強力な理由なしには実行できません。以下の表現イデオロギーに関連しています。

_a = b = c;
_

これにより、cbに割り当てられ、結果の値baに割り当てられます。これは、あなたが思うかもしれないことに反して、次のコードとnot同等です:

_a = c;
b = c;
_

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

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

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

Notecopy/swapイディオムを支持して上記を避けるべき場合があります。この特定のケースには必要ありませんが、次のようになります。

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

これは、クラスコピーアクターを使用してコピーを作成し、例外セーフスワッピングを使用して交換を実行するために行います。その結果、着信コピーはオブジェクトの古い内臓を離れる(そして破棄する)一方で、オブジェクトはそこの所有権を引き継ぎます。 コピー/スワップのイディオムについてはこちらをご覧ください 、およびその長所と短所。


必要に応じてconst参照によりオブジェクトを渡す

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

これを変更:

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

anythingのコピーは作成されないため、より効率的なコードが作成されます。


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

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


概要

_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
_
66
WhozCraig

の代わりに typedef struct { ... } pos;あなたはstruct pos { ... };。ここでの問題は、定義前にposタイプ名を使用していることです。名前を構造体定義の一番上に移動すると、構造体定義内でその名前を使用できます。

さらに、typedef struct { ... } name;パターンはC主義であり、C++にはあまり意味がありません。

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

inlineメソッドは、同じメソッドが複数のオブジェクトファイルで定義されている場合、リンカーエラーをトリガーしません。リンカーは、すべて同じ実装であると仮定して、1つを除いてすべてを無視します。インラインメソッドによる動作の変更:現在では、関数をインライン化するかどうかに関するコンパイラの決定に影響を与えず、関数の実装をすべての翻訳単位で利用できるようにするだけで、コンパイラにoption関数をインライン化する場合、そうすることが有益だと判断した場合)

6
cdhowie

これを試して:

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);
    }
 };  
3
Krozark
  1. bool operator ==(pos a)const {-このメソッドはオブジェクトの要素を変更しません。
  2. bool operator ==(pos a){-オブジェクトの要素を変更する場合があります。
2
maskotky