Por que o `std :: basic_ios` possui um construtor público?

15

std::basic_iostem um construtor público :

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

Na IMO, a única razão para uma classe ter um construtor público é usar uma instância autônoma dessa classe em um programa. Se uma classe existe apenas para ter outras classes dela (como parece ser o caso basic_ios), todos os construtores da classe devem ser protected. Os construtores de std::ios_baseestão todos protegidos. Mas, por alguma razão, os projetistas do padrão tornaram esse construtor basic_iospúblico.

basic_iosé usado como uma classe base para vários tipos de fluxo e não posso imaginar um caso de uso em que você teria um que não fosse pelo menos um basic_istreamou basic_ostream. Existe um?

Spencer
fonte

Respostas:

1

A outra razão para uma classe ter um construtor público é ter essa assinatura do construtor disponível para construir um objeto derivado:

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

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

    public:
    A(void*);
    };

 A a(10);

O construtor deve ser público na classe base, porque uma declaração de uso de um construtor de base não altera a acessibilidade do construtor herdado.

Oliv
fonte
2
Parece razoável, exceto após o fato de que o basic_iosctor que toma uma basic_streambuf*conta é público desde antes de você poder fazer using B::B;. Eu espero que implementações antigas tenham apenas um proxy ctor: A(int x) : B(x) {}- que funcione bem mesmo se Bo ctor estiver protected.
Ted Lyngmo
0

O que eu não percebi foi isso std::basic_istream, std::basic_ostreame std::basic_iostreamtambém tinha construtores públicos (cada um leva um std::basic_streambuf*).

Isso permite um análogo de polimorfismo de programação genérica, na mesma linha que o idioma pimpl.

Ou seja, dessa forma, você pode criar um tipo de streambuf especializado e usá-lo em um basic_[io] streamsem precisar criar classes de fluxo especializadas. (A funcionalidade é limitada: você não pode atribuir um novo buffer ao mesmo fluxo e deve acompanhar externamente a vida útil e a propriedade do buffer).

Os especializados basic_[io] fstreame basic_[io] stringstreamcontêm uma instância completa do tipo de buffer associado. Isso significa que uma instância de um tipo de fluxo especializado funcionará apenas com seu buffer interno e não outro, nem mesmo um do mesmo tipo. O uso de um basic_[io] bruto streamé uma solução alternativa (desajeitada) para isso.

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
fonte