Dlaczego `std :: basic_ios` ma konstruktora publicznego?

15

std::basic_iosma publicznego konstruktora :

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

IMO, jedynym powodem, dla którego klasa ma konstruktora publicznego, jest użycie autonomicznej instancji tej klasy w programie. Jeśli klasa istnieje tylko po to, aby inne klasy z niej wywodziły się (jak się wydaje basic_ios), wszystkie konstruktory klasy powinny być protected. Wszystkie konstruktory std::ios_basesą chronione. Ale z jakiegoś powodu projektanci standardu basic_iosupublicznili tego konstruktora .

basic_iosjest używany jako klasa podstawowa dla kilku typów strumieni i nie mogę przewidzieć przypadku użycia, w którym miałbyś taki, który nie byłby przynajmniej a basic_istreamlub basic_ostream. Czy jest jeden

Spencer
źródło

Odpowiedzi:

1

Innym powodem, dla którego klasa ma konstruktor publiczny, jest dostępność tej sygnatury konstruktora do skonstruowania obiektu pochodnego:

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

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

    public:
    A(void*);
    };

 A a(10);

Konstruktor musi być publiczny w klasie podstawowej, ponieważ deklaracja użycia konstruktora podstawowego nie zmienia dostępności odziedziczonego konstruktora.

Oliv
źródło
2
Wydaje się rozsądny, z wyjątkiem basic_iosafaik, biorąc pod uwagę , że ctor biorący basic_streambuf*był publicznie, zanim było to możliwe using B::B;. Oczekuję, że stare implementacje miały po prostu proxy ctor: A(int x) : B(x) {}- który działa dobrze, nawet jeśli Bctor jest protected.
Ted Lyngmo
0

Nie zauważyłem tego std::basic_istream, std::basic_ostreama std::basic_iostreamtakże miałem publicznych konstruktorów (każdy bierze a std::basic_streambuf*).

Pozwala to na generyczny programujący analog polimorfizmu, w tym samym stylu co idiom pimpl.

Oznacza to, że w ten sposób możesz utworzyć specjalistyczny typ streambufa i używać go w basic_[io] streambez konieczności tworzenia specjalistycznych klas strumienia. (Funkcjonalność jest ograniczona: nie możesz przypisać nowego bufora do tego samego strumienia i musisz zewnętrznie śledzić żywotność bufora i jego własność).

Wyspecjalizowane basic_[io] fstreami basic_[io] stringstreamzawierają pełne wystąpienie powiązanego typu bufora. Oznacza to, że instancja wyspecjalizowanego typu strumienia będzie działać tylko ze swoim wewnętrznym buforem, a nie innym, nawet jednym tego samego typu. Korzystanie z surowego basic_[io] streamjest (niezgrabne) obejściem tego problemu.

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
źródło