0

C ++で演算子をオーバーロードする主な目的は何ですか?

以下のコードでは<<>>がオーバーロードされています。そうすることの利点は何ですか?

#include <iostream>
#include <string>

using namespace std;

class  book {
    string name,gvari;
    double cost;
    int year;
    public:
    book(){};

    book(string a, string b, double c, int d) { a=name;b=gvari;c=cost;d=year; }
    ~book() {}
    double setprice(double a) { return a=cost; }
    friend ostream& operator <<(ostream& , book&);
    void printbook(){
        cout<<"wignis saxeli "<<name<<endl;
        cout<<"wignis avtori "<<gvari<<endl;
        cout<<"girebuleba "<<cost<<endl;
        cout<<"weli "<<year<<endl;
    }
};

ostream& operator <<(ostream& out, book& a){
    out<<"wignis saxeli "<<a.name<<endl;
    out<<"wignis avtori "<<a.gvari<<endl;
    out<<"girebuleba "<<a.cost<<endl;
    out<<"weli "<<a.year<<endl;
    return out;
}

class library_card : public book {
    string nomeri;
    int raod;
    public:
    library_card(){};
    library_card( string a, int b){a=nomeri;b=raod;}
    ~library_card() {};
    void printcard(){
        cout<<"katalogis nomeri "<<nomeri<<endl;
        cout<<"gacemis raodenoba "<<raod<<endl;
    }
    friend ostream& operator <<(ostream& , library_card&);
};

ostream& operator <<(ostream& out, library_card& b) {
    out<<"katalogis nomeri "<<b.nomeri<<endl;
    out<<"gacemis raodenoba "<<b.raod<<endl;
    return out;
}


int main() {
    book A("robizon kruno","giorgi",15,1992);
    library_card B("910CPP",123);
    A.printbook();
    B.printbook();
    A.setprice(15);
    B.printbook();

    system("pause");
    return 0;
}
4

8 に答える 8

7

使用する必要はありませ。これは単なる便利な方法であり、ユーザー定義型を組み込み型のように動作させる方法です。

たとえば、operator <<をオーバーロードすると、整数や文字列と同じ方法で本をストリーミングできます。

cout << "Book #" << n << " is " << books[n] << endl;

そうでない場合は、次のように同じことを書く必要があります。

cout << "Book #" << n << " is ";
books[n].printbook();
cout << endl;

同様に、Fractionクラスを作成し、それにoperator +を指定すると、整数を使用するのと同じ方法で分数を使用できます。

クラスが何らかの形でネイティブ型のように動作するかどうかは、設計上の選択が難しい場合があります(たとえば、文字列のoperator +は意味がありますか?)が、重要なのはC++で選択できるということです。

于 2012-06-15T22:02:59.610 に答える
2

演算子をオーバーロードする<<と、coutに渡されたときに、指定した方法でオブジェクトを出力に書き出すことができます。

それ以外の場合、coutはアドレスをオブジェクトに書き出すだけです。

于 2012-06-15T22:02:44.710 に答える
2

演算子のオーバーロードの目的は、主に構文糖衣です。それは醜いものを素敵に見せます。しかし、それはインターフェースを統合することでもあり、インターフェースを統合する重要な理由は、この場合は特にテンプレートを使用した多形性です。

素敵な複素数クラスComplexがあり、複素数型と倍数型で機能させたい正弦のテイラー級数近似が必要だとします。

*、などの演算子のオーバーロードをサポートしている場合は=/次のように記述できます。

template<typename T>
T sin(T t)
{
  T t2 = t*t;
  return t*(1 - t2/6 + (t2*t2)/120 );
}

オーバーロードなどができない場合は*/doubleとComplexのインターフェイスを統合するためのヘルパークラスが必要になるため、醜くなり始めます。これがどのように見えるかを示します。(私はまだのオーバーロードを許可operator=しています、さもなければそれはさらに悪化します)。

template<typename T>
T sin(T t)
{
  T t2 = helper<T>::mult( t, t );
  T t4 = helper<T>::mult( t2, t2 );
  T s(1);
  helper<T>::sincrement( &s, -1./6, t2);
  helper<T>::sincrement( &s, -1./120, t4);
  return helper<T>::mult( t, s );
}

template<>
struct helper<double>
{
  static double mult( double a, double b) { return a*b; }
  static void sincrement( double * v, double s, double x) { *v += s*x; }
}

template<>
struct helper<Complex>
{
  static Complex mult( Complex a, Complex b ) { return a.mult(b); }
  static void sincrement( Complex * v, double s, Complex x ) { v->add( x.scale(s) ); }
}

演算子のオーバーロードは醜く、実際に起こっていることを隠すことができることがわかりましたが、正しく使用すると、このようなケースがはるかに理解しやすくなると思います。

于 2012-06-23T00:56:24.813 に答える
1

代わりにメンバー関数を簡単に使用できます。ほとんどの場合、これは「シンタックスシュガー」を提供するだけです。たとえば、一部の言語では、2つの文字列を追加すると連結されます。

stringOne = stringOne + stringTwo;

のようなメンバー関数で簡単に実装できますが

stringOne.concat(stringTwo);
于 2012-06-15T22:02:13.260 に答える
1

演算子のオーバーロードにより、ポリモーフィズムの特殊なケースが可能になります。

私が考えることができる最良の例は、+演算子がオーバーロードされた文字列クラスです。

この場合、意味のない2つの文字列を「追加」する代わりに、演算子がオーバーロードされて文字列を連結します。

あなたの質問に答えるために、特にオーバーロード演算子は(場合によっては)より読みやすく保守しやすいコードを生成することができます。ただし、1人の人にとって「意味のある」ことは、コードを保守している人にとっては意味がない場合があります。

于 2012-06-15T22:03:08.900 に答える
1

オーバーロードされた演算子を使用すると、その演算子をオーバーロードする必要がある標準ライブラリアルゴリズムを使用できます。

例えば:

struct wtf{ wtf(int omg): omg(omg){} int omg; };

wtf operator+ (wtf const &omg, wtf const &lol)
{
    return wtf(omg.omg+ lol.omg);
}

#include <iostream>
#include <numeric>

int main()
{
    wtf lol[3]= { wtf(1), wtf(2), wtf(3) };
    std::cout<< std::accumulate(lol, lol+ 3, wtf(0)).omg;
}

6

于 2012-06-18T08:10:13.810 に答える
1

C ++の特徴は、オブジェクトの動作の基本的な目的として、オブジェクトを値で渡すことです。これにより、JavaやObjective-Cなどの参照セマンティクス指向の言語と比較して、オブジェクトの動作が大幅に変わります。

これらの言語の1つでは、プリミティブ型とオブジェクトの使用方法が明確に区別されます。つまり、プリミティブを大量にコピーし、演算子を含む式に貼り付けます。オブジェクトは主にそれらをインスタンス化し、それらのメソッドを呼び出し、それらへの参照を関数に渡します-C ++では、プリミティブを使用するのとほとんど同じ方法でオブジェクトを使用できます。これにより、C ++プログラマーが対処しなければならない多くの複雑な問題が発生します。たとえば、オブジェクトの有効期間、オブジェクトが左辺値か右辺値か(つまり、オブジェクトが表示される式の外に存続期間がある場合)などです。

あなたの質問が提起する1つのことは、クラスが<<と>>をオーバーロードする理由です。C ++標準ライブラリは、iostreamクラスにこの規則を使用し、参照セマンティクスベースの言語とのもう1つの大きな違いを強調しています。値セマンティクス指向の言語では、クラスの継承は、オブジェクトで何をしたいかを完全に記述するには不十分です。オブジェクトが<<および>>をオーバーロードしてデータをリソースに出し入れする場合、iostreamやios_baseなどから継承していなくても、iostreamの概念を満たしていると大まかに言えます。これの意味は2つあります。

  1. このタイプの値を式に入れて<<を使用すると、期待どおりに動作します。
  2. このタイプをパラメーターとして使用してテンプレートをインスタンス化し、オブジェクトに対してoperator <<を呼び出すと、コードは正常にコンパイルされます。

C ++ 11(次のバージョンに延期された)には、このアイデアを言語で形式化するConceptsという機能が追加される予定だったため、上記のコンセプトという単語を意図的に使用しました。現在の状況は、一種のダックタイピングです。テンプレートが特定の演算子を型で使用する場合、型がその演算子を提供する場合はコンパイルされ、提供されない場合は、演算子が実際に何であるかに関係なくコンパイルされます。を意味します。operator <<はその一例です。元の意味では、整数型の場合は「左符号ビットシフト」を意味しますが、iostreamの概念を使用している場合は、「右側のオブジェクトからデータをストリームする」を意味します。左側のオブジェクトに」。

于 2012-06-18T09:46:04.263 に答える
0

<<および>>演算子をオーバーロードする主な目的は、C ++標準ライブラリの精神でAPIを作成することです。そのため、経験豊富なC++プログラマーが型を使用するのがより自然になります。

このようにして、演算子<<および>>は、STLストリームで使用される場合、挿入/抽出演算子として知られています。Cからは、それらは単なるビットシフト演算子でした。

標準のC++の領域では、彼らはその意味を獲得し、そのための新しい命名法さえも受けたので、すでに確立されたプログラミング用語を再利用するのは良いことです。

さて、もともとC ++の作成で、なぜそれがストリーム操作のためにこのようになったのですか?シフト演算子を取得し、それらを挿入および抽出演算子としてラベル付けすることによって、私にはわかりませんが、シフト演算子の外観を考えると、挿入/抽出の概念をより適切に表現するための好みの問題かもしれません。と再利用するスーツ。

于 2012-06-15T22:04:59.890 に答える