←検索窓の楽しみ方
  ショッピングモール  掲示板ランキング


【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら



 本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール   掲示板1こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧

No.3595

オブジェクトの配列に対してのoperator++のオーバーロード
投稿者---kaz(2005/03/28 17:51:14)


前回の質問(コピーコンストラクタについて)のプログラムに関連しての質問です。

配列に対してのオペレータのオーバーロードを実現したいのですが、方法がわかりません?
フレンド関数で++をオーバーロードしようとしたのですが、エラーにひっかかります。

MapArray operator++(MapArray &o,int notused){
    cout << "im called. " << end;
    // ここでバリューをふやす処理
    return o;
}


int main(){
    MapArray wc("ww 1 rr 2");
    
    wc++; // これではなくて
 
    wc["test"]++; //これを実現したいのですが    
    
    return 0;
}


この

wc++;

だとコンパイルがとおるのですが、

wc["test"];

のほうはコンパイルがとおりません。
エラーの内容は以下の通りです。

error: non-lvalue in increment

どうかわかるかたよろしくお願いします。


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:オブジェクトの配列に対してのoperator++のオーバーロード 3596 monkey 2005/03/28 18:28:40


No.3596

Re:オブジェクトの配列に対してのoperator++のオーバーロード
投稿者---monkey(2005/03/28 18:28:40)


>error: non-lvalue in increment

左辺値じゃないものをインクリメントしようとしているからです。
[]演算子が++演算子を適用しようとするデータ(オブジェクト)の参照を返さなくてはなりません。



この投稿にコメントする

削除パスワード

No.3597

Re:オブジェクトの配列に対してのoperator++のオーバーロード
投稿者---kaz(2005/03/28 21:28:26)


>>error: non-lvalue in increment
>
>左辺値じゃないものをインクリメントしようとしているからです。
>[]演算子が++演算子を適用しようとするデータ(オブジェクト)の参照を返さなくてはなりません。

貴重なご意見ありがとうございます。アドバイスしていただいたとうり、やってみたのですが、

int& MapArray::operator[](string key){
    int *num = 0;
    for(Element* elem=mTop; elem!=NULL; elem=elem->getNext()){
        if (elem->getKey() == key){
            num = (int*)elem->getValue();
            return *num;
        }
    }
    add(key,0);
    return *num;
}   

すごく強引な感じが。。。こんなものなのでしょうか?コンパイルはとうりました。。。
が、実行したところやはりERRORが。

 2244 handle_exceptions: Exception: STATUS_ACCESS_VIOLATION

とのことですが、なにがいけないんでしょうか?operatorは以下のようにフレンドで
やってます。

MapArray& operator++(AssocArray &o,int notused){
    cout << "i am called" << endl;
    return o;
}

MapArray& operator++(AssocArray &o){
    cout << "i am called" << endl;
    return o;
}


メインのなかで

MapArray wc("AA 4 BC 3"),wcc("CC 5 DD 4 BC 5");
wc["DD"]++;

としたのですが、operator++がよばれてないようです。
聞いてばかりでもうしわけないのですが、どうかよろしくお願いします。


この投稿にコメントする

削除パスワード

No.3598

すいません、まちがえました。エラーは解決しましたが。。
投稿者---kaz(2005/03/28 21:35:52)


すいません、まちがえてました。int *num = new int(0)でした。
でも、やはりoperator++がよばれません。
よろしくおねがいします。

<pre>int& MapArray::operator[](string key){
int *num = new int(0);
for(Element* elem=mTop; elem!=NULL; elem=elem->getNext()){
if (elem->getKey() == key){
num = (int*)elem->getValue();
return *num;
}
}
add(key,0);
return *num;
}

MapArray& operator++(AssocArray &o,int notused){
cout << "i am called" << endl;
return o;
}

MapArray& operator++(AssocArray &o){
cout << "i am called" << endl;
return o;
}
</pre>
>
>メインのなかで
>
>MapArray wc("AA 4 BC 3"),wcc("CC 5 DD 4 BC 5");
>wc["DD"]++;
>
>としたのですが、operator++がよばれてないようです。
>聞いてばかりでもうしわけないのですが、どうかよろしくお願いします。


この投稿にコメントする

削除パスワード

No.3600

Re:すいません、まちがえました。エラーは解決しましたが。。
投稿者---RAPT(2005/03/28 22:37:51)


monkeyさんのレスをきちんと読みましょう。
> []演算子が++演算子を適用しようとするデータ(オブジェクト)の参照を
> 返さなくてはなりません。

int* num; は何でしょうか。
当該関数を抜けたら無効になる自動変数を変更して何になるというのでしょうか。
elem->mValue を変更するのが目的なのでは?

だとすると、elem->mValue の参照を返すことになります。
# でもそのままだとアクセス権が無いが。

それから、参照を返す場合、自動変数を返してはいけません。
関数が返す参照は、関数を終了しても有効な変数である必要があります。
# そうでなければ、アクセス違反となります(今回のケース)。



この投稿にコメントする

削除パスワード

No.3602

リファレンスへの変換方法。
投稿者---kaz(2005/03/28 23:17:07)


ほんとうにご意見感謝します。RAPTさんのおっしゃられるような関数内で宣言したものを
リファレンスで返さないということが理解できません。この関数内で
elem->getValue()はintをかえしてきます。そして、0を返す場合。これらをリファレンスとして変換する方法がどうしてもみつかりません。なにか根本的に間違っているのでしょうか?
以下のようにやってみたのですが、operator++はよばれませんでした。
関数内で宣言したintをリファレンスとして返す方法がこれ以外にあるのでしょうか?
どうかよろしくお願いします。

int& AssocArray::operator[](string key){
    int *num = new int(0);
    for(Element* elem=mTop; elem!=NULL; elem=elem->getNext()){
        if (elem->getKey() == key){
            num = new int(elem->getValue());
            elem->setValue(*num);
            return *num;
        }
    }
    add(key,*num);
    return *num;
}   



この投稿にコメントする

削除パスワード

No.3603

Re:リファレンスへの変換方法。
投稿者---しっぽ(2005/03/29 00:53:24)


kaz のコードについて不思議に思ったこと
(1) AssocArray ってなんですか?
(2) operator++ を friend 関数にする意義ってなんでしょうか?
(3) wc["DD"] って AssocArray クラスもしくはその派生クラスなんでしょうか?
(4) wc["DD"] って int 型とは違うのでしょうか?

operator++ を friend にするなんて考えてもみたことが無かったので(2)については是非
知りたいです。



この投稿にコメントする

削除パスワード

No.3609

Re:コピーコンストラクタについて2
投稿者---kaz(2005/03/29 08:13:11)


>kaz のコードについて不思議に思ったこと
>(1) AssocArray ってなんですか?
すいません、MapArrayです。名前を変えてたもので。。


>(2) operator++ を friend 関数にする意義ってなんでしょうか?
え、なぜfriendクラスでしてはいけないんでしょうか?

>(3) wc["DD"] って AssocArray クラスもしくはその派生クラスなんでしょうか?
説明不足ですいません。
MapArray wc;
wc["DD"];
wc["AA"];

です。

>(4) wc["DD"] って int 型とは違うのでしょうか?
Elementのフィールドにあるint型をかえしているのですが、この方法ではどうも
wc["DD"]++;ができないようで。。。

>operator++ を friend にするなんて考えてもみたことが無かったので(2)については是非
>知りたいです。
私は本当にまだC++はじめたばかりです。きっとかなり変なことばかりしているんですね。
ご指摘ありがとうございます。調べます。


この投稿にコメントする

削除パスワード

No.3612

追記です。
投稿者---kaz(2005/03/29 08:36:38)


ソースコードはこの下の”コピーコンストラクタについて”のスレッドにはっています。


この投稿にコメントする

削除パスワード

No.3605

Re:リファレンスへの変換方法。
投稿者---RAPT(2005/03/29 01:26:22)


> 関数内で宣言したintをリファレンスとして返す方法がこれ以外にあるのでしょうか?

ありますが、ここで必要なのは下記のような使用方法では?
# というか、さっきも書いたように、自動変数を参照で返すのはダメです。
# ってことは、自動変数で無ければよい、ってこと。
# static 変数とか、クラスのメンバ変数とか、グローバル変数とか。
# すなわち、その関数を抜けてもインスタンスが有効ならば良い。got it?

class T
{
public:
    int m_val;
    int& foo()
    {
        return m_val;
    }
};



この投稿にコメントする

削除パスワード

No.3611

Re:コピーコンストラクタについて2
投稿者---kaz(2005/03/29 08:32:04)


すいません、今は仕事場でソースコードがないのでコンパイルできないんですが、
グローバルでint DEFAULT_VALUE = 0; を宣言しておいて使えということですか?

int& MapArray::operator[](string key){
    for(Element* elem=mTop; elem!=NULL; elem=elem->getNext()){
        if (elem->getKey() == key){
            return elem->getValue();
        }
    }
    add(key,0);
    return DEFAULT_VALUE;
}   


今まではずっとJAVAばかりでC++にかなり戸惑っております。


この投稿にコメントする

削除パスワード

No.3613

Re:すいません、まちがえました。エラーは解決しましたが。。
投稿者---REE(2005/03/29 10:20:48)


まず、Element::getValue()を呼んでも、その戻り値は要素のコピーなので、その参照を返したところでもとの要素は変更されません。
よって、Element::getValue()を参照を返すように変更するか、参照を返す、別の関数を作成して使う必要があります。

次に、int& MapArray::operator[](string key)で返るのは、intの参照ですので、それをインクリメントしても、以下の関数が呼ばれることはありません。これらの関数は今回の用途に対しては無意味で、不要なものです。

>MapArray& operator++(AssocArray &o,int notused){
> cout << "i am called" << endl;
> return o;
>}
>
>MapArray& operator++(AssocArray &o){
> cout << "i am called" << endl;
> return o;
>}

もし呼ばれるとしたら、int& operator++(int &o)のような関数です。
※ これは実際には定義できません。


この投稿にコメントする

削除パスワード

No.3606

Re:オブジェクトの配列に対してのoperator++のオーバーロード
投稿者---かずま(2005/03/29 02:55:08)


> メインのなかで
>
> MapArray wc("AA 4 BC 3"),wcc("CC 5 DD 4 BC 5");
> wc["DD"]++;
>
> としたのですが、operator++がよばれてないようです。

STL(Standard Template Library) の map を使えば簡単なんですがねえ。
#include <iostream>
#include <sstream>
#include <map>
using namespace std;

class Map : public map<string, int> {
public:
    Map(string);
};

Map::Map(string str)
{
    istringstream is(str);  string key;  int value;
    while (is >> key >> value) insert(value_type(key, value));
}

int main()
{
    Map wc("CC 5 DD 4 BC 5");
    wc["DD"]++;
    for (Map::iterator it = wc.begin(); it != wc.end(); ++it)
        cout << it->first << ' ' << it->second << '\n';
}



この投稿にコメントする

削除パスワード

No.3610

Re:コピーコンストラクタについて2
投稿者---kaz(2005/03/29 08:15:56)


プログラム書いていただいて申し訳ないんですが、C++の初歩の練習ということで。MapやVectorなどはつかわずにということなんです。すいません。最初に書いとくべきでした。


この投稿にコメントする

削除パスワード

No.3615

とりあえず動くものはできました。
投稿者---kaz(2005/03/29 21:19:39)


とりあえず動くものはできたのですが、いろいろな部分で疑問がいっぱいです。
ソースはちょっと長いのでインターフェイスだけはります。

class Element {
    public:
        //Element();
        //Element(string key);
        Element(string key,int val);
        ~Element();

        string getKey() const;
        int& getValue();
        Element* getNext() const;
        void setValue(int newValue);
        void insert(Element* elem);
        void removeNext();
    
    private:
        string mKey;
        int mValue;
        Element* mNext;
};

class MapArray {
    
    public:
        /** Default Constructor */
        MapArray();
        
        /** Constructor with a string argument which may consists of one or more key-value pair*/
        MapArray(string str);

        /** Copy Constructor */
        MapArray(const MapArray &o);

        /** Destructor */
        ~MapArray();
        
        MapArray& operator=(const MapArray &o);
        int& operator[](string key);        
        void insert(string key,int val);
        void erase(string key);
        void begin() const;
        bool end() const;
        void next() const;
        string key() const;
        int value() const;
        int count(string key) const;
        int size() const;
        friend ostream& operator<<(ostream &, const MapArray&);
        friend MapArray& operator+(MapArray &a, const MapArray &b);
        friend MapArray& operator+=(MapArray &a, const MapArray &b);
        friend MapArray& operator-(MapArray &a, const MapArray &b);
        friend MapArray& operator-=(MapArray &a, const MapArray &b);
        
    /** the private variables of the MapArray */
    private:
        /** the number of element that is stored in this list */
        int mSize;
        
        /** the top element of this list */
        Element* mTop;

        /** the last element of this list */
        Element* mTail;
        
        /** the internal pointer of this list */
        mutable Element* mCussor;

        void add(string key,int val);
};
>


みなさんのおかげで[]++にはとりあえず成功しました。ただプログラムをいじっているうちに
たくさん疑問がわいてきたのでどうか教えてください。
Elementクラスの中のプライベート変数を

int mValue;

としたのですが、これらを扱う関数の引数を

void insert(string key,int& val);

のようにリファレンスにすることもできます。int とするのとどちらのほうがよいのでしょうか?また、その理由はなぜでしょうか?

これがようやくできたoperator[]なんですが、

insert(key,0);

これは許されるのでしょうか?このゼロもローカルで宣言している変数と同じ扱いなのでしょうか?特にプログラムに影響がないように思えるのですが。もし、これがだめであるとしたら
どうすればいいのかわかりません。staticやGLOVALだと値をシェアしてしまいますし、他に方法があれば教えてください。よろしくお願いします。

int& MapArray::operator[](string key){
    insert(key,0); // insertはkeyがなければ新しくElementをつくりaddします。、keyがあれば無視します。
    Element* elem = NULL;
    for(elem=mTop; elem!=NULL; elem=elem->getNext()){
        if (elem->getKey() == key){
            break;
        }
    }
    return elem->getValue();
}   


あと、もうひとつだけ。int& getValue() のようにリファレンスをかえすファンクションに
constをつけることができません。これはなぜでしょうか?


この投稿にコメントする

削除パスワード

No.3616

Re:とりあえず動くものはできました。
投稿者---REE(2005/03/29 21:33:00)


>Elementクラスの中のプライベート変数を
>
>int mValue;
>
>としたのですが、これらを扱う関数の引数を
>
>void insert(string key,int& val);
>
>のようにリファレンスにすることもできます。int とするのとどちらのほうがよいのでしょうか?また、その理由はなぜでしょうか?

intのままでいいでしょう、理由はリファレンスにする必要がないからです。もし、リファレンスにすると、下記のinsert(key,0);などが出来なくなります。

>これがようやくできたoperator[]なんですが、
>
>insert(key,0);
>
>これは許されるのでしょうか?このゼロもローカルで宣言している変数と同じ扱いなのでしょうか?特にプログラムに影響がないように思えるのですが。

これは問題ありません。
なぜならば、これによって出来たElementはこの関数を抜けても削除されないため、そのメンバ変数の参照はそのまま有効です。

>あと、もうひとつだけ。int& getValue() のようにリファレンスをかえすファンクションに
>constをつけることができません。これはなぜでしょうか?

この戻り値のリファレンスを介して、メンバ変数の値が変更される可能性があるからです。
変更されないことを保証するために、constのリファレンスを返すようにすれば、constをつけられます。
このとき、constのあるものとないものは同時に存在できます。

例:
int& getValue()
const int& getValue() const



この投稿にコメントする

削除パスワード

No.3623

Re:とりあえず動くものはできました。
投稿者---kaz(2005/03/30 17:39:44)


非常に丁寧な解説ありがとうございます。

>この戻り値のリファレンスを介して、メンバ変数の値が変更される可能性があるからです。
>変更されないことを保証するために、constのリファレンスを返すようにすれば、constをつけられます。
>このとき、constのあるものとないものは同時に存在できます。
>
>例:
>int& getValue()
>const int& getValue() const

同時に存在できることを確認したのですが、

elem->getValue();

この場合どちらのファンクションが
よばれるかは呼ばれた先でその値が変えられているかどうかでコンパイラーが判断して
決めるのでしょうか?それだと二つ持つ意味が無いような気がするのですが。


この投稿にコメントする

削除パスワード

No.3624

Re:とりあえず動くものはできました。
投稿者---REE(2005/03/30 19:08:10)


>同時に存在できることを確認したのですが、
>
>elem->getValue();
>
>この場合どちらのファンクションが
>よばれるかは呼ばれた先でその値が変えられているかどうかでコンパイラーが判断して
>決めるのでしょうか?それだと二つ持つ意味が無いような気がするのですが。

どちらが呼ばれるかは、elemがconstかどうかで決まります。
両方あることで、constでないときは値の参照と変更ができ、
constの時でも、値の参照が出来るようになります。



この投稿にコメントする

削除パスワード

No.3639

みなさん、ありがとうございました。
投稿者---kaz(2005/04/02 14:29:55)


みなさん、本当にありがとうございました。おかげさまでいろいろなことを理解することができました。すごく感謝してます。また何かあったときはよろしくお願いします。


この投稿にコメントする

削除パスワード

No.3644

Re:みなさん、ありがとうございました。
投稿者---かずま(2005/04/06 02:25:47)


もう解決されたようなのですが、このプログラムは参考になりますか?
#include <iostream>
#include <sstream>

typedef std::string string;

class Element {
    string mKey;  int mValue;  Element *mNext;
    Element(const string& key, int value, Element *next)
        : mKey(key), mValue(value), mNext(next) { }
    friend class MapArray;
};

class MapArray {
    Element *mHead, *mCurr;
public:
    MapArray() { mHead = new Element("", 0, 0); set_begin(); }
    MapArray(const MapArray& a);
    MapArray(const string& str);
    ~MapArray();
    MapArray& operator=(const MapArray& a);
    int& operator[](const string& key);
    void set_begin() { mCurr = mHead->mNext; }
    void next()   { mCurr = mCurr->mNext; }
    bool is_end() { return mCurr == 0; }
    string& key() { return mCurr->mKey; }
    int& value()  { return mCurr->mValue; }
};

MapArray::MapArray(const MapArray& a)
{
    Element *p = mHead = new Element("", 0, 0);
    for (Element *q = a.mHead; q->mNext; q = q->mNext, p = p->mNext)
        p->mNext = new Element(q->mNext->mKey, q->mNext->mValue, 0);
    set_begin();
}

MapArray::MapArray(const string& str)
{
    mHead = new Element("", 0, 0);
    std::istringstream is(str);  string key;  int value;
    while (is >> key >> value) (*this)[key] = value;
    set_begin();
}

MapArray::~MapArray()
{
    for (Element *p= mHead; p; ) {
        Element *next = p->mNext;  delete p;  p = next;
    }
}

MapArray& MapArray::operator=(const MapArray& a)
{
    if (&a == this) return *this;
    for (Element *p= mHead->mNext; p;) {
        Element *next = p->mNext;  delete p;  p = next;
    }
    for (Element *p = mHead, *q = a.mHead->mNext; q; q = q->mNext, p = p->mNext)
        p->mNext = new Element(q->mKey, q->mValue, 0);
    set_begin();
    return *this;
}

int& MapArray::operator[](const string& key)
{
    Element *p;
    for (p = mHead; p->mNext; p = p->mNext) {
        if (p->mNext->mKey == key) return p->mNext->mValue;
        if (p->mNext->mKey > key) break;
    }
    p->mNext = new Element(key, 0, p->mNext);
    return p->mNext->mValue;
}

int main()
{
    MapArray wc("XX 5  YY 7");
    wc["ZZ"];
    wc["YY"]++;
    MapArray wc2(wc); // copy constructor
    wc2 = wc;         // assignment operator
    for (wc2.set_begin(); !wc2.is_end(); wc2.next())
        std::cout << wc2.key() << ' ' << wc2.value() << '\n';
}



この投稿にコメントする

削除パスワード

No.3662

すごすぎます。
投稿者---kaz(2005/04/15 00:02:04)


久しぶりに掲示板の方におとずれたらすごいのがのっててびっくりしました。見れば見るほど自分の書いたコードが恥ずかしくなります。。しっかりと勉強させていただきます。感動ものです。このコードは。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧




掲示板提供:Real Integrity