2011-02-11

C++の雑学

C++の、特に知らなくても問題ない知識。

virtual関数のデストラクターをもつクラスの、deallocation functionがdeleted定義されていたり、名前が曖昧である場合、エラーとなる。

struct X
{
    virtual ~X() { } // OK、グローバルスコープのoperator deleteが発見される
} ;

struct Y
{
    virtual ~Y() { } // エラー、operator deleteはdeleted定義されている。
    void operator delete( void * ptr ) = delete ;
} ;

これは、クラスYのvirtualなデストラクターを定義した時点でエラーになる。たとえ、クラスYのオブジェクトをnew、deleteしていなくても、ましてや、プログラム中でクラスYのオブジェクトを使っていなかったとしても、関係はない。デストラクタの定義の時点でのエラーである。

これは、デストラクターがvirtual関数である動的な型をもつオブジェクトは、かならず、delete式に渡せるということを保証するための仕様である。

メンバー関数としてのoperator deleteのオーバーロード関数は、staticメンバー関数である。つまり、virtual関数にはできない。ただし、デストラクターがvirtual関数の場合、operator deleteも動的に呼び出される。

struct Base
{
    // staticメンバー関数
    void * operator new( std::size_t size ) { return ::operator new(size) ; }
    void operator delete( void * ptr ) { ::operator delete( ptr ) ;}
} ;

struct Derived : Base
{
    // Baseのメンバーを隠す
    void * operator new( std::size_t size ) { return ::operator new(size) ; }
    void operator delete( void * ptr ) { ::operator delete( ptr ) ; }
} ; 

int main()
{
    Base * ptr = new Derived() ;
    delete ptr ; // Base::operator deleteが呼ばれる
} 

なぜならば、呼び出すべきoperator deleteは静的に決定されるからだ。

もし、クラスがvirtual関数のデストラクターを持っていた場合、delete式では、動的な方に応じて、deallocation functionが実行時に選ばれる。

struct Base
{
    // staticメンバー関数
    void * operator new( std::size_t size ) { return ::operator new(size) ; }
    void operator delete( void * ptr ) { ::operator delete( ptr ) ; }
    virtual ~Base() { }
} ;

struct Derived : Base
{
    // Baseのメンバーを隠す
    void * operator new( std::size_t size ) { return ::operator new(size) ; }
    void operator delete( void * ptr ) { ::operator delete( ptr ) ; }

    // 暗黙のデストラクターはvirtual関数になる
} ; 

int main()
{
    Base * ptr = new Derived() ;
    delete ptr ; // Derived::operator deleteが呼ばれる
} 

ブロックスコープ内の宣言は、外側のスコープの名前を隠す。これは、関数にも適用される。

void f(int) { }

int main()
{
    void f() ; // ブロックスコープ内の関数の前方宣言、void f(int)を隠す

    f( 0 ) ; // エラー、void f(int)は見つからない
}

void f() { }

ブロックスコープでは、関数宣言を行わないほうがいいだろう。もっとも、ブロックスコープで関数宣言ができるということを知っているC++ユーザーの方が少数派かもしれないが。

No comments: