¿Hay algún uso para que una clase contenga solo (por defecto) miembros privados en c++?


Los miembros de una clase son por defecto privados en c++.

Por lo tanto, me pregunto si hay algún uso posible de crear una clase que tenga todos sus miembros (variables y funciones) configurados por defecto en privado.

En otras palabras, ¿existe alguna definición de clase significativa sin ninguna de las palabras clave public, protected ¿o private?

Author: mr_T, 2014-09-11

6 answers

Hay un patrón, utilizado para la protección de acceso, basado en ese tipo de clase: a veces se llama patrón de clave de acceso (véase también clean C++ granular friend equivalent? (Respuesta: Expresión Abogado-Cliente) y ¿Cómo nombrar este patrón de protección de acceso orientado a claves?).

Solo un amigo de la clase key tiene acceso a protectedMethod():

// All members set by default to private
class PassKey { friend class Foo; PassKey() {} };

class Bar
{
public:
  void protectedMethod(PassKey);
};

class Foo
{
  void do_stuff(Bar& b)
  {
    b.protectedMethod(PassKey());  // works, Foo is friend of PassKey
  }
};

class Baz
{
  void do_stuff(Bar& b)
  {
    b.protectedMethod(PassKey()); // error, PassKey() is private
  }
};
 25
Author: manlio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:58:22

Envío de etiquetas. Se utiliza en la biblioteca estándar para las etiquetas de categoría de iteradores , con el fin de seleccionar algoritmos que pueden ser más eficientes con ciertas categorías de iteradores. Por ejemplo, std::distance puede implementarse algo como esto: (de hecho, se implementa casi exactamente así en gnu libstdc++, pero lo he modificado ligeramente para mejorar la legibilidad)

template<typename Iterator>
typename iterator_traits<Iterator>::difference_type
distance(Iterator first, Iterator last)
{
      return __distance(first, last,
             typename iterator_traits<Iterator>::iterator_category());
}

Donde __distance es una función que está sobrecargada para comportarse de manera más eficiente para std::random_access_iterator_tag (que es una estructura vacía, pero podría ser fácilmente una clase) , simplemente usando last - first en lugar del comportamiento predeterminado de contar cuántos incrementos se necesitan para obtener first a last.

 18
Author: Benjamin Lindley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-11 10:55:58

¿Adquisición de recursos en toda la aplicación ?

#include <iostream>

class C {
    C() {
        std::cout << "Acquire resource" << std::endl;
    }


    ~C() {
        std::cout << "Release resource" << std::endl;
    }

    static C c;
};


C C::c;

int main() {
    return 0;
}

Como se indica en los comentarios a continuación, tengo me importa una aplicación industrial que tenía que "bloquear" algún dispositivo de hardware mientras el programa se estaba ejecutando. Pero uno probablemente podría encontrar otro uso para esto ya que, después de todo, es solo un caso "degenerado" o RAII.


En cuanto al uso de métodos "privados" fuera del bloque de declaración: aquí uso un miembro estático. Así, es declarado en un punto donde los miembros privados son accesibles. No estás limitado a constructor / destructor. Puede incluso (ab)usar métodos estáticos y luego invocar métodos privados instance usando una interfaz fluent :

class C {
    C() { std::cout << "Ctor " << this << std::endl; }
    ~C() { std::cout << "Dtor" << this << std::endl; }

    static C* init(const char* mode) {
        static C theC;

        std::cout << "Init " << mode << std::endl;
        return &theC;
    }

    C* doThis() {
        std::cout << "doThis " << std::endl;

        return this;
    }

    C* doThat() {
        std::cout << "doThat " << std::endl;

        return this;
    }

    static C *c;
};


C *C::c = C::init("XYZ")
            ->doThis()
            ->doThat();

int main() {
    std::cout << "Running " << std::endl;
    return 0;
}

Ese código sigue siendo válido (ya que todos los miembros C son accesibles en el punto de la declaración de C::c). Y producirá algo así:

Ctor 0x601430
Init XYZ
doThis 
doThat 
Running 
Dtor0x601430
 15
Author: Sylvain Leroux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-12 09:09:23

Significativa? Una buena práctica? Probablemente no, pero aquí va:

class DataContainer {
    friend class DataUser;
    int someDataYouShouldNotWorryAbout;
};

class DataUser {
public:
    DataUser() {
        container.someDataYouShouldNotWorryAbout = 42;
    }
private:
    DataContainer container;
};
 7
Author: AlexanderBrevig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-11 10:42:32

No, no tiene sentido crear una clase sin variable miembro público y/o funciones, ya que no habría una forma de acceder a nada en la clase. Incluso si no se indica explícitamente, la herencia también es privada.

Claro, podría usar friend como se sugiere, pero crearía una convolución innecesaria.


Por otro lado, si usas struct y no class para definir una clase, entonces obtienes todo público. Eso puede tener sentido.

Por ejemplo:

struct MyHwMap {
  unsigned int field1 : 16;
  unsigned int field2 : 8;
  unsigned int fieldA : 24;
};
 1
Author: BЈовић,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-11 13:12:32

Un caso ciertamente feo de hace muchos, muchos años y no en C++, pero la idea todavía se aplicaría:

Hubo un error en la biblioteca de tiempo de ejecución. En realidad, arreglar el código ofensivo causaría otros problemas, así que escribí una rutina que encontró el código ofensivo y lo reemplazó con una versión que funcionó. La encarnación original no tenía ninguna interfaz más allá de su creación.

 0
Author: Loren Pechtel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-11 17:40:52