CStringを基本クラスにするクラスには、文字列は代入できない?

[戻る]
ガラ 2011/02/16(水) 11:52:47
MFC VC++ 6.0
XP

CStringを基本クラスに持つCOverCstringクラスを作成しましたが、
コンスタント文字列を代入しようとするとエラーがでていまいます。
なにかいい手はありませんでしょうか?

CString            a ;
COverCString        b ;

a = "ABCD" ;
b = "ABCD" ; //<−ここでエラーになります

***エラーメッセージ
error C2679: 二項演算子 '=' : 型 'char [5]' の右オペランドを扱う演算子は定義されて
いません。

tenteku 2011/02/16(水) 13:59:56
何を拡張しようとしたか分かりませぬが一例として

COverCstring(LPCTSTR str)
{ operator=(str); }
LPCTSTR operator=(LPCTSTR str)
{ return CString::operator=(str); }

こんな感じですかね。かなり基礎的なC++レベルの内容なので
人に聞くより本読んだ方が早いのでは。operatorがわからんようだと
満足にCStringの拡張できるか怪しい気がします。頑張ってください

PATIO 2011/02/16(水) 14:42:20
エラーメッセージから問題点が把握できると解決手段も出てきそうですが。

エラーメッセージの意味が理解できないのは多分クラス周りの知識が
足りない所為かなと思います。
tentekuさんも書かれていますが、自分の知識が怪しいと感じたら
文法書や入門書に立ち返って知識の確認をする事をお勧めします。
一度読んだだけではなかなか定着しませんが、そうやって繰り返す事で
定着して行くと思います。

PATIO 2011/02/16(水) 14:46:42
追伸:
エラーメッセージが出るとつい解決する方向に向いてしまい、
エラーメッセージの内容をきちんと理解しようとせずに進んで
しまおうとする事があります。
ですが、実際にはエラーの内容をきちんと理解する事が
解決の早道になります。問題点を把握してそれに対して対応するのと
単純に解決方法だけを求めて解決するのでは、起こった問題に対する
知識の深さがまるで違います。
エラーを解決する事も勿論目的の一つですが、
そこから問題点の原因を追究してそれを理解する事も大きな目的です。
今後に繋げる為にもエラー内容を理解して何処に原因があるのかを
深く追求する事をお勧めします。

ガラ 2011/02/16(水) 15:31:08
tentekuさん、PATIO さん、レスありがとうございます。
operator=をオーバライドするのかな?とはおもっていたのですが、
void  COverCString::operator =(const LPCSTR lpszCharSet)
{
    int    Length = strlen(lpszCharSet) ;
    memcpy(this->GetBuffer(Length + 1),lpszCharSet,Length + 1) ;
    this->ReleaseBuffer() ;

 }
というようにしていました。
上の記述では、+=のときに正常動作しませんでした。
他のオペレータに影響があるなら、オーバライドしてはいけない?かもと
思い質問を上げてみました。

tentekuさんのコーディングを試してみましたが、+=のときに正常動作しません。
ソースを追うと、
メモリが足らなくなって、再割り当てするときにおかしいみたいです。
他で、メモリーリークしているのかな?と思っていま調べています。

tenteku 2011/02/16(水) 16:32:23
自分の環境では動きますけど。
例)
class CStringA : public CString  
{
public:
 CStringA(){};
 virtual ~CStringA(){};

 CStringA(LPCTSTR str) { operator=(str); }
 LPCTSTR operator=(LPCTSTR str) { return CString::operator=(str); }
};

CStringA a = "hoge";
CStringA b, c;

a = "piyo";
b = c = "fuga";
a += b;
b += "hogera";

ここにない何かをOverloadをしているのではないかと推測しますが
それは兎も角、C2679に対しての修正の意味がご理解いただければ
operator+=が動かないと質問はこないと思いますが現状これ以上は
本人しか分からないので回答しようもない。頑張ってください。。。

PATIO 2011/02/16(水) 17:31:33
operator=とoperator+=は別々の演算子になるので直接の原因に
なっているのかは疑問です。
派生して追加した機能に関しては説明が有りませんので
何とも言いかねますが、親クラスのメンバーを弄っているのなら
それが原因で実装上の矛盾が発生している可能性があります。
派生クラス側で追加したメンバーの操作のみであれば、
既存のコードへの影響はないかもしれませんが、
親クラスのメンバー変数を弄るのであれば、
親クラスの実装はきちんと把握した上で矛盾が起こらないように
弄る必要があるはずです。

現象が起こっている所が直接の原因とは限りません。
特にメモリ周りの不具合の場合、原因箇所と発現箇所が全く別の場所である可能性があり
ます。
起きている現象を一つ一つ追いかけた上で何がおかしくて動かないのかを
追いかけるしかありません。

仲澤@失業者 2011/02/16(水) 17:50:22
VC6なら、CStringA は「セーフ」ですが、現在のコンパイラだとペケですね。

ガラさんは、一度class CStringの定義を見てみたら良いと思うのですが、
もうご覧になったでしょうか(AFX.h)。複数の operator = ()
メンバがありますよねぇ。んで、

b = "ABCD" ; //<−ここでエラーになります

これは書き換えると以下の様になるわけですが、

b.operator = ( "ABCD");

このoperator = ()は、たくさんある中のどれが要求されているのか
考えてみたらわかると思います。

ガラ 2011/02/16(水) 18:18:28
tentekuさん、わざわざ、コーテディング⇒コンパイル⇒実行していだだき、ありがとう
ございます。まことにお手間をとっていただいて、申し訳ございません。
いまのところ、どの関数がどういう悪いことをしているのか、あれこれ、いっぱいオー
バロードしているので、しぼりきれていません。
ぜんぜん違うところを探索していたような感じですが、
>COverCstring(LPCTSTR str)
>{ operator=(str); }
>LPCTSTR operator=(LPCTSTR str)
>{ return CString::operator=(str); }
すごく簡単で、スマートですね。とても参考になりました。ありがとうございます。

PATIOさん、いつも、わたしの理解に大きな意味を持つコメントありがとうございます。
とても感謝しております。
>operator=とoperator+=は別々の演算子になるので直接の原因に
>なっているのかは疑問です。
ということは、どうも、別件のようですね。

>起きている現象を一つ一つ追いかけた上で何がおかしくて動かないのかを
>追いかけるしかありません。
根気よくがんばってみます。

仲澤@失業者 さん、レスありがとうございます。
>これは書き換えると以下の様になるわけですが、
>b.operator = ( "ABCD");

全然しりませんでした。AFX.hを見てみます。

ガラ 2011/02/16(水) 20:44:22
メモリーリーク箇所を見つけました。

COverCString buffer ;
:
:
:
buffer.SetAt(0,buffer[idx]) ;
buffer.SetAt(1,(char)NULL) ; //この記述が問題だったようです
↓
buffer = pNode->buffer.Mid(idx,1) ;//上の2行をこのように変更して対応しました。

idx は、bufferのインデックスを示すint型

bufferの内容をidxで示された1文字にしたかったので、
buffer.SetAt(0,buffer[idx]) ;
buffer.SetAt(1,(char)NULL) ;
としましたが、これがメモリーリークの原因だったようです。
CString::SetAt()のマニュアルを読むと、リロケートしない関数で、
しかも、第1引数は、どこに挿入するかの0から始まるindexなのですが、
CString::GetLength()より小さい数でなければならないそうです。
わたしのイメージでは、bufferのサイズが1のときでも、もう一文字分NULLの入る
分はあるんじゃないのかな?とおもっていたのですが、なぜかだめなようです。

tenteku 2011/02/17(木) 10:13:00
単にIndexの文字にしたいのであればGetAt(idx)の方が単純です。
もっともこれはこれで別のOverloadを要求されるようなのであえて使う必要はないかも

仲澤@失業者さん
指摘ありがとうございます。これってwchar関連の指摘でしょうか?
CStringT (CStringA/W)

仲澤@失業者 2011/02/17(木) 11:42:04
>指摘ありがとうございます。これってwchar関連の指摘でしょうか?
>CStringT (CStringA/W)

ですね。現在ではCStringAはMFCで定義済みですので、
いずれ、コンパイラとライブラリを新しくすることを考えると、
VC6上であれ、class CStringAを自前で定義するのは避けるべきと
考えました(vv;)。

ryo 2011/02/17(木) 12:20:54
この流れでいうのはなんだけど
CStringって、継承して使うことを想定してあるようには思えない

CStringの利点をつぶし、手間をかけてまで継承して使いたい理由ってなんでしょう?

ガラ 2011/02/17(木) 13:49:30
tentekuさん、仲澤@失業者さん、ryo さん、レスありがとうございます。
何をつくってるかといえば「構文解析」をつくっています。
で、いろいろと、関数をくつっていますが、
たとえば、後ろから文字列を検索する関数が必要なので、
int  CSString::ReverseFind(const LPCSTR lpszCharSet)
{
    CString RightOfBuffer ;
    int    i,i_max = this->GetLength() ;
    for(i = 1 ; i <= i_max ; i++) { 
        RightOfBuffer = this->Right(i) ;
        if (RightOfBuffer.Find(lpszCharSet) == 0) {
            return(i_max - i) ;
        }
    }

    return(-1) ;
}
なのをつくっています。
CString::ReverseFindは(VC++6.0では)
int ReverseFind( TCHAR ch ) const;
しかありませんでした。

hirocco 2011/02/17(木) 13:59:38
クラスにこだわらないで
LPCTSTRを引数にとる関数を作ったほうが楽じゃないかな?
CStringの継承はたぶん大掛かりすぎるかな

なんちゃって

PATIO 2011/02/17(木) 15:57:02
hiroccoさんの話に同感。

必要な機能と実装範囲が噛み合っていない気がします。
C++言語で実装するにしてもクラスとして実装する意味がない物を
相手にするのであれば、クラスで実装する必要は無いと思います。
他の関数との関数名の衝突を避けるために独自の名前空間で
関数を実装するのありだと思いますし。

ガラ 2011/02/18(金) 07:32:45
hirocco さん、PATIOさんレスありがとうございます。
>CStringの継承はたぶん大掛かりすぎるかな
>hiroccoさんの話に同感。

まだ、ちょっとピンときませんが、よくアドバイスをしてくださるお二人がそういうの
であれば、好みの問題ではなく、そういうものなのかな・・とおもいます。

>他の関数との関数名の衝突を避けるために独自の名前空間で
関数を実装するのありだと

なるほどそういうことで使うんですね。
ありがとうございます。

解決したとします。他のみなさんもありがとうございました。
いろいろ話が聞けて、あれこれわかりました。

ガラ 2011/02/18(金) 08:24:07
[[解決]]
すいませんチェックわすれてました

古いスレッドには追加発言できません。