Visual C++ .net で出来ること

更新日: 2003年 9月 28日(日)

今更(^^ゞ

もう出荷され1年以上経過してしまってますが、さすがにそろそろ移行しようかなと思われている方もいるかもしれないので、.net から出来るようになったことをまとめます。

ちなみに今回の記事は、 一番新しい Visual C++ .net 2003(7.1) ではないのでご注意を。

共変 ( Covariant )

仮想関数で、戻りが自分のクラスのポインタを渡すケースとして、派生して自分のコピーを渡したいと考えます。今までは以下のように記述する必要がありました。

class Base 
{
public:
	// コピーコンストラクタがあるつもり
	virtual Base* copy() {
		return new Base( this );
	}
};

class Sub : public Base 
{
public :
	// コピーコンストラクタがあるつもり
	Base* copy() {
		return new Sub( this );
	}
};

この問題点してあげられるのは、親キャストにアップキャストしていることです。せっかくなら、派生クラスを戻り値にしたいところです。

Visual C++ .net からは、以下のような記述が出来るようになりました。

class Sub : public Base 
{
public :
	// コピーコンストラクタがあるつもり
	Sub* copy() {
		return new Sub( this );
	}
};

上のようなコードを書いてもコンパイルしません。共変を使うとこのような記述が可能になります。ちなみに virtual を付けなければオーバーライド出来ます。ただ、仮想関数にならないので使えませんが・・・。

ちょっと調査不足でいまいち共変の意味がわからないのですが、簡単な話は上のようなことが出来るということでしょう。

static const メンバ変数

定数の書き方を簡略化できます。

class Base
{
public:
	static const int MAX_COUNTER = 100;
};

クラス内で、定数を定義する場合にでも使ってください。

ちなみに VC6 では以下のように書かないとコンパイル通りません。

class Base
{
public:
	static const int MAX_COUNTER;
};

const int MAX_COUNTER = 100;	// ソースファイルに書く

static const 変数を使うと、#define とは違い、名前空間が有効になる利点があることでしょう。

throw std::badalloc @ new

new でメモリ確保した場合 std::bad_alloc を投げられるようになります。ただ、そのまま意識無く VC.net を使っても badalloc を投げてくれないので注意してください。

bad::alloc で受けるようにすためには、新しい標準ライブラリのヘッダー( ".h" の拡張子がないヘッダー ) を古い標準ライブラリより先にインクルードされるようにするだけでOKです。

ちなみに VC7 ではVC6 と同じように例外を投げないようにすることも可能です。VC7.1では古い標準ライブラリを使うことが出来なくなったようなので、7.1ではこのような事が出来なくなったのかもしれません。ただ、明示的に例外を返さない方法もあるので問題はないと思いますが。

#include <new>

int main(){
	try {
		new int[512*1024*1024];
	} catch(std::bad_alloc &ba){
	} catch(...){
	}
}

実行速度を優先する場合は、noThrow

for 文

.net では、for 文の中で定義する変数のスコープ範囲が修正されました。修正前は、for文以降もスコープが続いていましたが、修正後は for 文内しかスコープがありません。

今まで下のように書いていたコードが

for( int i = 0; i < 100; i++ ) {
	// 処理
}
for( i = 0; i < 100; i++ ) {
	// 処理
}

下のようになりました。

for( int i = 0; i < 100; i++ ) {
	// 処理
}
for( int i = 0; i < 100; i++ ) {
	// 処理
}

他に VC6 でも新しい仕様の for 文を使うこと方法を下に示します。

#define for if(0){}else for

for を "if(0){}else for" に置換してあげると

for( int i = 0; i < 100; i++ ) {
	// 処理
}
// 下のように置き換わる(*展開後がわかりやすくなるようにインデント、改行、
// {} を付けておきました )
if(0){
}
else{
	for( int i = 0; i < 100; i++ ) {
		// 処理
	}
}

else のスコープの外へ出るので int i の名前がスコープアウトする仕組みになっています。

逆に .net でもまだ・・・

Koenig ルックアップ (Argument Dependent name Lookup)は、依然と利用できません。

namespace NameSpace {
	struct DataList;
	void func( DataList& );
}

void function()
{
	NameSpace::DataList data;
	func( data );
}

func 関数の呼び出して、本来なら NameSpace::func を記述するべきところですが、引数の型より名前空間の異なる関数を探し出してくれます。