:第三章 クラスの詳細

クラスの詳細。だんだんこう、C++って考えることが多くて大変! という気分になってきた。

オブジェクトの代入

myclass a,b;
a = b;

とすると、aにbがコピーされる。javaとかと違って変数が同じクラスを参照するわけではなく、配列なども含めたメンバ変数も全部コピーされる。
メンバ変数にポインタを持ち、デストラクタでそれをフリーするようなクラスでオブジェクトの代入が行われた場合、同じ領域が二回freeされるのでエラーがおきる。

関数へのオブジェクトの引き渡し

オブジェクトを引数として渡した場合、デフォルトでは全て値渡し=オブジェクトのコピーが渡される。関数内で引数のオブジェクトに変更を加えても、外には影響がない。
関数から抜けるときに引数のコピーのオブジェクトのデストラクタが呼び出されるので、デストラクタにfree()がある場合、オブジェクトの代入と同様の問題が発生する。(デストラクタが二回呼び出される)

class myclass{
     char *s;
   public:
     myclass(char a){s = (char *)malloc(strlen(a));strcpy(s,a);}
     ~myclass(){free(s);}
};

   myclass f(myclass a){
      return a;
   }//ココでm0のコピーのデストラクタが呼び出され、sが解放される。

main(){
   myclass m0("test");
   f(m0);
   return 0;
}//ココでm0のデストラクタが呼び出され、sをもう一度解放しようとしてエラーになる。

という感じで良いのかな。今適当にかいたから動かなそうなコードだけど。

オブジェクトのポインタを渡せば、関数内でオブジェクトを弄ることが出来る。

関数からのオブジェクトの返し

関数からオブジェクトを返すとき、オブジェクトを呼び出し元に返した後(オブジェクトがコピーされて返される)、オブジェクトは破棄される。その際デストラクタが呼び出されるので、以下略。

例の3.3.2でデストラクタが三回呼び出されると書いてあるけど、実行してみたら二回しか呼び出されなかった。

class samp2{
    char *s;
public:
    samp2() {s = '\0';}
    ~samp2() {cout << "free s\n";if (s) free(s);}
    void show() {cout << s << "\n";}
    int set(char *str);
};

int samp2::set(char* str){
    s = (char *)malloc(strlen(str)+1);
    if(!s){
        cout << "Memory Allocation Error\n";
        exit(1);
    }
    strcpy(s , str);
}


samp2 input(){
    char s[80];
    samp2 str;

    cout << "input string:";
    cin >> s;

    str.set(s);
    return str;//strが一時オブジェクトにコピーされ戻り値として元ルーチンに返される。
}//1.スコープから外れるときにstrのデストラクタが呼び出される

int main(){
    samp2 ob;
    ob = input();//2.一時オブジェクトのデストラクタが呼び出される
    ob.show();
    return 0;
}//3.obのデストラクタが呼び出される。


勿論エラーにはなったけど。どうも2.が実行されていない気がする。
なんだろう、コンパイラの違いかなあ。
そもそも、一時オブジェクトが何かよくわからない。

フレンド関数

class A{
    int private;
  public:
    friend void f(A a);
}

void f(A a){
    return a.private
}

という感じで、あるクラスのフレンド関数は、そのクラスの非公開メンバにアクセス出来る。別のクラスのメンバ関数をフレンド関数にすることも出来る。friend int B::f(A a)とかそういうような。
今一用途が分からないけど、役立つ理由は以下の三点らしい。

また後のページで言及があるみたい。