¿Por qué `std :: basic_ios` tiene un constructor público?

15

std::basic_iostiene un constructor público :

explicit basic_ios (std::basic_streambuf<CharT,Traits>* sb);

En mi opinión, la única razón para que una clase tenga un constructor público es usar una instancia independiente de esa clase en un programa. Si una clase existe solo para que otras clases desciendan de ella (como parece ser el caso basic_ios), todos los constructores de la clase deberían estarlo protected. Los constructores de std::ios_baseestán todos protegidos. Pero, por alguna razón, los diseñadores del estándar hicieron de éste un constructor de basic_iospúblico.

basic_iosse usa como una clase base para varios tipos de flujo, y no puedo imaginar un caso de uso en el que tenga uno que no sea al menos un basic_istreamo basic_ostream. ¿Hay uno?

Spencer
fuente

Respuestas:

1

La otra razón para que una clase tenga un constructor público es tener esta firma de constructor disponible para construir un objeto derivado:

struct B{
  B(int);
  protected:
  ~B();
  };

 struct A:B{
    private://no effect.
    using B::B;

    public:
    A(void*);
    };

 A a(10);

El constructor debe ser público en la clase base porque una declaración de uso de un constructor base no cambia la accesibilidad del constructor heredado.

Oliv
fuente
2
Parece razonable, excepto afaik, la basic_iostoma de un ctor basic_streambuf*ha sido pública desde antes de que pudieras hacerlo using B::B;. Espero que las implementaciones antiguas solo tuvieran un ctor proxy: A(int x) : B(x) {}- que funciona bien incluso si Bel ctor lo es protected.
Ted Lyngmo
0

Lo que no noté fue eso std::basic_istream, std::basic_ostreamy std::basic_iostreamtambién tenía constructores públicos (cada uno toma un std::basic_streambuf*).

Esto permite un análogo de programación genérica de polimorfismo, en la misma línea que el idioma de pimpl.

Es decir, de esta manera puede crear un tipo de flujo de flujo especializado y usarlo en un basic_[io] streamsin tener que crear clases de flujo especializadas. (La funcionalidad es limitada: no puede asignar un nuevo búfer a la misma secuencia, y debe realizar un seguimiento externo de la vida útil y la propiedad del búfer).

Los basic_[io] fstreamy basic_[io] especializados stringstreamcontienen una instancia completa del tipo de búfer asociado. Esto significa que una instancia de un tipo de flujo especializado solo funcionará con su búfer interno y no otro, ni siquiera uno del mismo tipo. Usar un basic_[io] sin formato streames una solución (torpe) para esto.

template<class C, class TR>
class snazzy_filebuf: public std::basic_streambuf<C, TR>
{
 protected:
   typename TR::int_type overflow(TR::int_type) override;
   typename TR::int_type underflow(TR::int_type) override;
   typename TR::int_type pbackfail(TR::int_type) override;
 public:
   snazzy_filebuf();
};

.....
snazzy_filebuf<char> buf;
std::basic_ostream<char> o_s(&buf); 

o_s << "Hello, world\n";
Spencer
fuente