2011-01-10

C++のちょっと知られていないこと

他のクラスのメンバー関数を、friend関数にできる。

struct Y
{
    void f() ;
} ;

struct X
{
    friend void Y::f() ; // OK
} ;

このように、他のクラスのメンバー関数をfriend宣言することで、クラスすべてのメンバーではなく、あるメンバーだけを、friendとすることができる。

オーバーライドしたvirtual関数のアクセス指定は、オーバーライドされるvirtual関数には影響を及ぼさない。

class Base
{
public :
    virtual void f() { } // publicメンバー
} ;

class Derived : public Base
{
private :
    void f() { } // Base::fをオーバーライド、privateメンバー
} ;

int main()
{
    Derived d ;
    d.f() ; // エラー、Derived::fはprivateメンバー

    Base & ref = d ;
    ref.f() ; // OK、Derived::fを呼び出す
}

Base経由で、privateメンバーであるDerived::fを呼び出すことができる。これは、virtual関数のアクセスチェックは、呼び出す時点での宣言により、静的に決定されるためだ。関数mainから、Base::fにはアクセスできるため、ref.f()という式はエラーにならない。後は、通常通り、virtual関数呼び出しによって、オブジェクトの型である、Derivedのfが、正しく呼び出される。

もちろん、いま執筆中の参考書には、これらの仕様も漏れ無く説明されている。

2 comments:

etc said...

似たような話で、gccやclangでこれが出来るのは何ででしょうね。なんかBCCだと公開水準を制限できないとか言って別のErrorになったような気がしますが。

struct Base
{
static void Example();
};

class Derived:public Base
{
Base::Example;
};

Derived::Example();// Error

江添亮 said...

BCCのような古代のコンパイラーを使ってはいけません。
その文法はAccess declarationといって、C++03ですらdeprecatedな文法です。使ってはいけません。
かわりにusing declarationを使いましょう。