Da Sie Vorlagen verwenden, dachte ich, dass der letzte Teil Ihrer Frage über das Verhindern einer anderen Klasse als Abgeleitet von einer Unterklasse von Base mit geeigneten Teilspezialisierungen durchgeführt werden könnte.
Das folgende Code-Snippet ist, was ich kam, aber die erforderliche Komplexität geht nur, um die Antwort von jalf zu verstärken. Ist es das wert? Wenn überhaupt, dann hat das mir geholfen, eine teilweise Spezialisierung besser zu verstehen, als eine Technik auszuarbeiten, die ich jemals in der Praxis anwenden würde.
Ich benutze COMMON, um einen gemeinsamen Template-Parameter zwischen Base und Derived und EXTRA anzugeben, um die zusätzlichen Parameter zu bezeichnen, die Sie sagen, Abgeleitet hat. Die tatsächliche Anzahl von diesen könnte alles sein, was ich zufällig ausgewählt habe, jeweils eins und zwei für diese jeweils.
// 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;
Dieser Code wurde mit gcc 4.3.2 getestet.
Beachten Sie, dass eine Alternative zur Friend-Deklaration darin besteht, den Konstruktor in der partiellen Spezialisierung von Base zu schützen, aber dies würde Klassen wie DishonestDerived erlauben zu arbeiten.
Ich würde einige Quellcode enthalten - da es Vorlagen beinhaltet. – sylvanaar
Wenn eine Klasse keinen virtuellen Destruktor hat, sollte man davon wahrscheinlich nicht dasdieren (das ist nur eine gute Programmierung). C++ erkennt, dass Sie manchmal die Grenzen strecken müssen und Sie trotzdem davon erben können. Dein Problem ist also keine Sprache, sondern eine pädagogische. –
Abstimmung: Entfernen Sie das Schlüsselwort/final-Tag, aber fügen Sie ** abgeleitete Klasse ** -Tag stattdessen – fmuecke