Pourquoi `std :: basic_ios` a un constructeur public?

15

std::basic_iosa un constructeur public :

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

OMI, la seule raison pour laquelle une classe a un constructeur public est d'utiliser une instance autonome de cette classe dans un programme. Si une classe existe uniquement pour que d'autres classes en descendent (comme cela semble être le cas pour basic_ios), tous les constructeurs de la classe devraient l'être protected. Les constructeurs de std::ios_basesont tous protégés. Mais, pour une raison quelconque, les concepteurs de la norme ont fait de ce constructeur un basic_iospublic.

basic_iosest utilisé comme classe de base pour plusieurs types de flux, et je ne peux pas imaginer un cas d'utilisation où vous en auriez un qui n'était pas au moins un basic_istreamou basic_ostream. Est-ce qu'il y a un?

Spencer
la source

Réponses:

1

L'autre raison pour qu'une classe ait un constructeur public est d'avoir cette signature de constructeur disponible pour construire un objet dérivé:

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

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

    public:
    A(void*);
    };

 A a(10);

Le constructeur doit être public dans la classe de base car une déclaration using d'un constructeur de base ne change pas l'accessibilité du constructeur hérité.

Oliv
la source
2
Cela semble raisonnable, sauf afaik, le basic_iosctor prenant un basic_streambuf*a été public depuis avant que vous ne puissiez le faire using B::B;. Je m'attends à ce que les anciennes implémentations aient juste un proxy ctor: A(int x) : B(x) {}- qui fonctionne bien même si Bctor l'est protected.
Ted Lyngmo
0

Ce que je n'ai pas remarqué, c'est que std::basic_istream, std::basic_ostreamet il std::basic_iostreamy avait aussi des constructeurs publics (chacun prend un std::basic_streambuf*).

Cela permet un analogue de programmation générique du polymorphisme, dans la même veine que l'idiome pimpl.

Autrement dit, de cette façon, vous pouvez créer un type streambuf spécialisé et l'utiliser dans un basic_[io] streamsans avoir à créer des classes de flux spécialisées. (La fonctionnalité est limitée: vous ne pouvez pas affecter un nouveau tampon au même flux, et vous devez garder une trace externe de la durée de vie et de la propriété du tampon).

Les basic_[io] fstreamet basic_[io] spécialisés stringstreamcontiennent chacun une instance complète du type de tampon associé. Cela signifie qu'une instance d'un type de flux spécialisé ne fonctionnera qu'avec son tampon interne et pas une autre, pas même une du même type. L'utilisation d'un basic_[io] brut streamest une solution de contournement (maladroite) à cela.

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
la source