템플릿을 사용하고 있기 때문에 파생되지 않은 클래스를 기본에서 하위 클래스로 만들지 못하게하는 것에 대한 질문의 마지막 부분은 적절한 부분 특수화를 사용하여 수행 할 수 있다고 생각했습니다.
다음 코드 스 니펫은 내가 생각해 냈지만 복잡성은 단지 jalf가 답을 강화하는 데에만 필요합니다. 그만한 가치가 있니? 이것이 도움이된다면 부분적 전문화를 이해하는 데 도움이 될 것입니다.
저는 COMMON을 사용하여 Base와 Derived 사이의 공유 템플릿 매개 변수를 나타내고 EXTRA를 사용하여 파생 된 추가 매개 변수를 나타냅니다. 이것들의 실제 숫자는 방금 내가 각각 이것들에 대해 1과 2를 고른 것이 될 수 있습니다.
// Forward declaration of class Derived
template< class COMMON
, class EXTRA1
, class EXTRA2 >
class Derived;
// Definition of general class template Base
template< class SUBCLASS
, class COMMON >
class Base
{
private:
Base() {}
};
// Definition of partial specialisation of template class Base to open up
// access to the constructor through friend declaration.
template< class COMMON
, class EXTRA1
, class EXTRA2 >
class Base< Derived< COMMON, EXTRA1, EXTRA2 >
, COMMON >
{
private:
Base() {}
friend class Derived< COMMON, EXTRA1, EXTRA2 >;
};
// Definition of class Derived
template < class COMMON
, class EXTRA1
, class EXTRA2 >
class Derived
: public Base< Derived< COMMON, EXTRA1, EXTRA2 >
, COMMON >
{
public:
static Derived* create() { return new Derived; }
private:
Derived() : Base< Derived< COMMON, EXTRA1, EXTRA2 >
, COMMON >()
{
}
};
// Definition of class HonestDerived.
// It supplies itself as the SUBCLASS parameter to Base.
template < class COMMON
, class EXTRA1
, class EXTRA2 >
class HonestDerived
: public Base< HonestDerived< COMMON, EXTRA1, EXTRA2 >
, COMMON >
{
public:
HonestDerived() : Base< HonestDerived< COMMON, EXTRA1, EXTRA2 >
, COMMON >()
{
}
};
// Definition of class DishonestDerived
// It supplies Derived rather than itself as the SUBCLASS parameter to Base.
template < class COMMON
, class EXTRA1
, class EXTRA2 >
class DishonestDerived
: public Base< Derived< COMMON, EXTRA1, EXTRA2 >
, COMMON >
{
public:
DishonestDerived() : Base< Derived< COMMON, EXTRA1, EXTRA2 >
, COMMON >()
{
}
};
template< class COMMON, class EXTRA1, class EXTRA2 >
class DerivedFromDerived
: public Derived< COMMON, EXTRA1, EXTRA2 >
{
public:
DerivedFromDerived() : Derived< COMMON, EXTRA1, EXTRA2 >()
{
}
};
// Test partial specialisation gives Derived access to the Base constructor
Derived< int, float, double >* derived
= Derived< int, float, double >::create();
// Test that there is no access to the Base constructor for an honest subclass
// i.e. this gives a compiler error
HonestDerived< int, float, double > honestDerived;
// Test that there is no access to the Base constructor for a dishonest subclass
// i.e. this gives a compiler error
DishonestDerived< int, float, double > dishonestDerived;
// Test that there is no access to the Derived constructor
// i.e. this gives a compiler error
DerivedFromDerived< int, float, double > derivedFromDerived;
이 코드는 gcc 4.3.2에서 테스트되었습니다.
친구 선언에 대한 대안은 Base의 부분 특수화에서 보호 된 생성자를 만드는 것이지만 DishonestDerived와 같은 클래스가 작동하도록하는 것입니다.
템플릿이 포함되어 있으므로 일부 소스 코드가 포함됩니다. – sylvanaar
클래스에 가상 소멸자가 없다면 아마도 좋은 프로그래밍이라고 생각하지 않아야합니다. C++은 가끔 경계를 확장하는 기능이 필요하고 어쨌든 상속을 허용 할 수 있음을 알고 있습니다. 그래서 문제는 언어가 교육적으로 문제가되지 않는다는 것입니다. –
투표 : 키워드/최종 태그를 제거하고 대신 ** 유도 클래스 ** 태그를 추가하십시오 – fmuecke