Index

HOME > プログラムTOP > C++



C++の壺・クラス篇2

 C++の基本テクニックのTipsです。
 クラス篇2では、クラスに付随する便利な機能と、それらの使用方法を扱います。
ページ項 目内 容
クラス篇1 クラスの基礎 クラスの宣言 / アクセス修飾子 / コンストラクタ / デストラクタ / メンバ / 静的メンバ / クラスの実装 / thisポインタ
クラスの継承 継承(派生) / メンバ / コンストラクタ / デストラクタ / オーバーライド / 仮想関数 / 抽象クラス
動的インスタンス クラスの実体の動的な作成と破棄
クラス篇2 friendキーワードfriendクラス / friend関数
constキーワード constオブジェクト / constメンバ関数 / constメンバ定数
演算子オーバーロード 演算子のオーバーロード / オーバーロード可能な演算子
クラス篇3 クラスの多重継承 複数のクラスを継承するクラスです
メンバ関数のinline化 処理速度を速める関数です
クラス・テンプレート 様々なデータ型を扱えるクラスです

sasaraan programming

Exposition

●friendキーワード

#include <stdio.h>     // printf
#include <conio.h>    // getch
#include <string.h>    // strcpy

// Alphaクラス ==============
class Alpha
{
private:
 @friend class Beta;
 Afriend char *GetName(Alpha *a);
    char Name[100];
public:
    Alpha() { strcpy(Name, "alpha");}
    ~Alpha() {}
};

// Betaクラス ==============
class Beta@
{
public:
    void SendName(Alpha *a) {
        strcpy(a->Name, "beta");
    }
};

// GetName関数 ===========
char *GetName(Alpha *a)A
{
    return a->Name;
}

// main関数 ===============
int main()
{
    Alpha A;
    Beta B;

    printf("%s\n", GetName(&A)); //"alpha"

    B.SendName(&A);
    printf("%s\n", GetName(&A)); //"beta"
	
    if (getch()) return 0;
}    
@friendクラス】
 クラス宣言の際、friend修飾子を使って、外部のクラスを friendクラス として登録することができます。通常、外部クラスからは、publicメンバ(派生クラスは protectedメンバまで)しかアクセスできませんが、friend で登録したクラスからは、privateメンバを含むそのクラスのすべてのメンバにアクセスすることができます。
 なお、friendの関係は一方通行です。また、継承もされません。

* 左記の例では、Betaクラスは、Alphaクラスの friendクラスです。Betaクラスからは、 SendName関数のように、Alphaクラスの privateメンバである Nameメンバにアクセスすることができます。


Afriend関数】
 クラスの宣言の際、friend修飾子を使って、外部の関数を friend関数 として登録することができます。通常、外部関数からは、publicメンバにしかアクセスできませんが、friend で登録した関数からは、privateメンバを含むそのクラスのすべてのメンバにアクセスすることができます。
 また、登録場所はどのアクセス修飾子のところでもかまいませんが、クラスのメンバとして扱うことはできません。

* 左記の例では、GetName関数は、Alphaクラスの friend関数です。GetName関数からは、Alphaクラスの privateメンバである Nameメンバにアクセスすることができます。

●constキーワード

#include <stdio.h>     // printf
#include <conio.h>    // getch

// Gammaクラス(宣言) ========

class Gamma
{
private:
    char *Name;
 Bconst int Index;
public:
    Gamma();
    ~Gamma();
 Achar *GetName() const;
 Cstatic const int ID = 999;
};

// Gammaクラス(実装) ========

Gamma::Gamma()
 : Name("gamma"), BIndex(0)
{
}

Gamma::~Gamma() 
{
}

char *Gamma::GetName() constA 
{
    return Name;
}

//main関数 ==================

int main()
{
 @const Gamma G;

    printf("%s\n", G.GetName());

    if (getch()) return 0;
}    
@constオブジェクト】
 クラスのインスタンスを作成する際、constキーワードで宣言すると、作成されたオブジェクトの内容を変更することができなくなります。この時、内容を変更をするしないに関わらず、すべてのメンバ関数の呼び出しもできなくなります。ただし、constメンバ関数のみは、呼び出しが可能です。

* 左記のサンプルで、main関数内の Gammaクラスのインスタンス G は constオブジェクトです。GetNameメンバが const宣言してあるので呼び出すことができます。


Aconstメンバ関数】
 クラスの宣言の際、constキーワードでメンバ関数を宣言すると、データ内容の変更をすることができなくなります。constメンバ関数以外のメンバ関数の呼び出しもできません。これにより、constオブジェクトからの関数呼び出しが可能となります。
 なお、constメンバ関数は、引数の後ろに const を記述して宣言します。さらに、const の記述は実装の際にも必要です。

* 左記のサンプルで、Gammaクラスの GetName は、constメンバ関数です。const宣言した Gammaクラスのインスタンスから呼び出すことができます。


Bconstメンバ定数】
 クラス宣言の際、constキーワードでデータメンバを宣言すると、データ内容の変更をすることができなくなります。
 ただし、コンストラクタで明示的に行う初期化の時だけ、値を設定することができます。 (例外として、Cstatic const 整数 は、クラス宣言時に初期化をすることが可能です。)

* 左記のサンプルで、Gammaクラスの Index は constメンバ定数です。ここでは、コンストラクタで明示的に 0 に初期化しています。この初期化は {}内では行えません。

●演算子オーバーロード

#include <stdio.h>     // printf
#include <conio.h>    // getch

// Pointクラス(宣言) ==========

class Point
{
public:
    int X;
    int Y;
 @void operator =(Point pt);
 @Point operator +(Point pt);
 @Point operator -(Point pt);
};

// Pointクラス(実装) ==========

void Point::operator =(Point pt)
{
    this->X = pt.X;
    this->Y = pt.Y;
}

Point Point::operator +(Point pt)
{
    Point a;
    a.X = this->X + pt.X;
    a.Y = this->Y + pt.Y;
    return a;
}

Point Point::operator -(Point pt)
{
    Point a;
    a.X = this->X - pt.X;
    a.Y = this->Y - pt.Y;
    return a;
}

// main関数 ==================

int main()
{
    Point pt1, pt2, pt3, pt4;
    pt1.X = 77;
    pt1.Y = 88;

    pt2 = pt1;              // X=77, Y=88
    printf("%d, %d\n", pt2.X, pt2.Y); 

    pt3 = pt1 + pt2;    // X=154, Y=176
    printf("%d, %d\n", pt3.X, pt3.Y); 

    pt4 = pt2 - pt3;    // X=-77, Y= -88
    printf("%d, %d\n", pt4.X, pt4.Y);

    if (getch()) return 0;
}    
@演算子のオーバーロード】
(オペレータ・オーバーロード)
 演算子の中には、再定義可能なものもあります。これらは左記のサンプルのように、クラスのメンバとして宣言・実装をすることができます。
 また、使用する時は、main関数内の "pt2 = pt1" のように、通常の演算子と同様に扱うことができます。あるいは、

 pt2.operator =(pt1);

のように、メンバであることを明示して記述することも可能です。

* 左記のサンプルでは、Pointクラスの宣言の際に、=、+、− の3つの演算子をオーバーロードしています。


【オーバーロード可能な演算子】
,(カンマ) &(アドレス)
&(ビットAND)^(ビットXOR)
|(ビットOR)~(1の補数)
!(論理NOT)&&(論理AND)
||(論理OR)( )(関数呼び出し)
+(単項プラス)-(単項マイナス)
+(加算)-(減算)
*(乗算)/(除算)
%(剰余)[ ](配列の添字)
++(インクリメント)--(デクリメント)
==(等しい)!=(等しくない)
<(より小さい)>(より大きい)
<=(以下)>=(以上)
<<(左シフト)>>(右シフト)
=(代入)+=(加算代入)
-=(減算代入)*=(乗算代入)
/=(除算代入)%=(剰余代入)
&=(AND代入)|=(OR代入)
^=(XOR代入)<<=(左シフト代入)
>>=(右シフト代入)->(メンバ選択)
*(ポインタ)->*(ポインタメンバ)
new(作成)delete(破棄)

www.sasaraan.net

(c) morijoh