ATL-Styleクラス(テンプレートベースクラス)定義のAVエラー


次に、典型的なATLスタイルのクラス定義を示します.
#include "stdafx.h"

#include "iostream.h"

template <class T>
class B1
{
public: 
    void SayHi() 
    {
        T* pT = static_cast<T*>(this); 
        pT->PrintClassName();
    }
protected:
    void PrintClassName()
    {
       cout<<"This is B1"; 
    }
};
 

class D1 : public B1<D1>
{
    // No overridden functions at all
};

 
class D2 : public B1<D2>
{
protected:
    void PrintClassName() 
    { 
       cout<<"This is D2"; 
    }
};

 
int main(int argc, char* argv[])
{
    D1 d1;
    D2 d2;
 
    d1.SayHi();    // prints "This is B1"
    d2.SayHi();    // prints "This is D2"
    return 0;
}

このコードは非常に惑わされ、完全に正しいように見えますが、コンパイルすると、エラーメッセージが表示されます:error C 2248:'D 2::PrintClassName':cannot access protected member declared in class'D 2'、つまりD 2::PrintClassNameメソッドにアクセスする際に、十分な権限がありません.
修正方法は簡単で、D 2::PrintClassNameの方法をpublicで修飾するだけです.
原因を分析するのも簡単で、しかもとても面白いです.d 1を呼び出す.SayHiはd 1のため問題ない.SayHiメソッドによって呼び出されたPrintClassNameメソッドは派生クラスD 1によって書き換えられず、依然としてB 1のPrintClassNameメソッドであり、SayHiメソッドと同じタイプのthisポインタを持つ.すなわち、それらは同じクラスに定義され、クラスメソッドが同類メソッドを呼び出すのは常に成功する.B 1::PrintClassNameメソッドをprivateに変更しても、正しいです.
同様に、d 2が呼び出される.SayHiに問題が発生します.原因はd 2です.SayHiメソッドによって呼び出されたPrintClassNameメソッドは派生クラスD 2によって書き換えられており、両者のthisポインタタイプはまったく異なる.すなわち、同じクラスに定義されていないため、権限チェックが必要です.