c++ - publicas - ejemplo de reglas de enlace poo
Cómo prohibir la herencia pública pero permitir la herencia privada(y protegida) (2)
C ++ 11 introdujo la palabra clave final
para prohibir futuras anulaciones o para prohibir la herencia. El ejemplo más común donde se puede usar es para el caso de clases que no están destinadas a ser utilizadas como clases base (tienen, por ejemplo, destructores no virtuales). Sin embargo, es posible que en algún momento deseamos tener una relación implementada en términos de dos clases (es decir, herencia private
), y no una relación is-a (herencia public
). Sin embargo, final
prohíbe ambos tipos de herencia.
Mi pregunta es la siguiente: ¿hay alguna forma de permitir private
herencia private
pero prohibiendo public
herencia public
(probablemente no directamente, pero al menos podemos "simularla")? En este caso, no habrá problemas incluso si usamos una clase con un destructor no virtual, ya que no podemos usar directamente la clase derivada a través de un puntero a la base, por lo que deberíamos estar bien.
Estoy pensando en un código como este:
class Base /*final*/ {}; // making it final prohibits both private and public inheritance
class PrivateDerived: private Base{}; // this should work
class PublicDerived: public Base{}; // this shouldn''t
int main()
{
PrivateDerived prvd;
PublicDerived pubd; // this should not compile
// Base* pBase = new PrivateDerived; // doesn''t work, so we are ok
}
¡Interesante pregunta! Si no te importa renunciar a la trivialidad del destructor, creo que lo siguiente hace el trabajo:
#include <type_traits>
template <typename T>
class Base {
protected:
~Base() {
static_assert(!std::is_convertible<T*,Base*>::value, "Invalid use of public inheritance.");
}
};
class Derived : public Base<Derived> {
};
int main() {
Derived d;
}
El código anterior no se compila: el static_assert
porque Derived*
es convertible a Base<Derived>*
. Sin embargo, si cambia la herencia a protected
o private
, el código se compila.
Desafortunadamente los usuarios todavía pueden dispararse en el pie
class Bad : public Base<Derived> {
};
No estoy seguro si esto es lo que está buscando o si esto lo ayudará en su caso. Sin embargo demostraré un comportamiento polimórfico.
Constructor protegido clase abstracta
class BaseProtected {
// ----- Member Variable Section -----
public:
// There Shouldn''t Be Public Variables In A Base Class Unless
// That Is The Behavior You Are Looking For - Keep In Mind
// Every Inherited Class & Outside Class Can Change Them.
protected:
// Member Variables Here To Be Shared With Each Derived Class
private:
// Member Variables Here To Be Used By Base Class Only
// ----- Member Function Section -----
public:
virtual ~BaseProtected(); // Virtual Destructor
void somefunc() const; // Common Function Between All Derived Class
virtual void allDerivedMustImplement() const; = 0 // Purely Virtual
protected:
// Default Constructor - Can Not Declare An Instance Of Base Class
BaseProtected(); // Abstract Class
// Protected Functions Shared Between Classes
// Protected Functions That Are Purely Virtual If Needed
private:
// Private Functions Used By Base Class Only
}; // BaseProtected
Clase Derivada Con Posible Herencia
class DerivedWithPossibleInheritance : public BaseProtected {
// ----- Member Variable Section -----
public:
// Public Member If Giving Free Access
protected:
// Protected Members If Being Inherited From
private:
// Private Members Unique To This Derived Class
// ----- Member Function Section -----
public:
DerivedWithPossibleInheritance(); // Default Constructor
virtual ~DerivedWithPossibleInheritance(); // Virtual Destructor
void uniqueFunctionForThisClass() const;
void allDerivedMustImplement() const override;
private:
// Private Functions Unique To This Class
}; // DerivedWithPossibleInheritance
Clase derivada que no puede ser heredada de
class DerivedClassCanNotBeInheritedFrom sealed : public BaseProtected {
// ----- Member Variable Section -----
public:
// Public Members Variables
protected:
// Should Not Have Member Variables Here For This Class Can Not Be Inherited from
private:
// Private Members Variables
// ----- Member Function Section ------
public:
DerivedClassCanNotBeInheritedFrom(); // Default Constructor
virtual ~DerivedClassCanNotBeInheritedFrom(); // Default Virtual Destructor
void anotherUniqueFunctionForThisClass() const;
void allDerivedMustImplement() const override;
protected:
// There Should Not Be Any Functions Here This Can Not Be Inherited From
private:
// Private Member Functions Here
}; // DerivedClassCanNotBeInheritedFrom
Lo que he demostrado aquí es la palabra clave sellada cuando se trabaja con herencia y polimorfismo. Si no desea que se derive su clase, utilice la palabra clave sellada.
En cuanto a la declaración de cualquier clase base, una clase independiente o una clase de singleton que tenga un Constructor privado, se necesita el uso de la palabra clave friend. Hay muchos tipos de implementaciones con las que se puede involucrar aquí para mostrarlas, pero el concepto de evitar que una clase sea heredada es el mismo. Personalmente no he usado la palabra clave final, pero he usado la palabra clave sellada y funciona muy bien.
No he utilizado la herencia de clases que no sean públicas. Entonces, responder a sus preguntas en términos de herencia protegida o privada no es algo con lo que esté realmente familiarizado. Pero tal vez el uso de la palabra clave sellada pueda ayudarlo.