Why is no qualification necessary?

后端 未结 4 635
梦如初夏
梦如初夏 2021-02-13 12:22

OK, I\'ll just post the complete program even though it has extraneous stuff and the code in question is the dead code…

#include 
#include         


        
相关标签:
4条回答
  • 2021-02-13 12:59

    Another observation is that ios_base::openmode works, but ios::openmode does not:

    class InFStream
        : public std::ifstream
    {
        // ...
        ios::openmode m1;       // error: ios does not name a type
        ios_base::openmode m2;  // ok
    }
    

    I think a1ex07 has found the crux of the matter: here again, ios_base is the name of a class, while ios is merely a typedef.

    And the difference is that the name of a class is a member of that class (9/2), and so can be looked up as the name of the type in InFStream (3.4.1/7 item 1) as it is a member of a base class of InFStream. But some typedef merely alongside the base class off in some other namespace can't be seen.

    [Standard section numbers from C++98.]

    0 讨论(0)
  • 2021-02-13 13:08

    When you derive from the class you have specify

    std::ifstream
    

    to be able to find the class in the std namespace.

    In the code itself you class derived from std::ifstream knows everything of ifstream.

    Inheritance of ifstream:

    ios_base -> ios -> istream -> ifstream
    
    0 讨论(0)
  • 2021-02-13 13:13

    Some thoughts about why you have to specify std::ifstream in constructor's initializer . I think typedef is the culprit - ifstream is defined as typedef basic_ifstream<char, char_traits<char> > ifstream;). If you change your constructor to

     explicit InFStream(
        char const*         filename,
        ios_base::openmode  mode =  ios_base::in | ios_base::out
    
        ):
        basic_ifstream<char,std::char_traits<char>>( filename, mode ){}
    

    you also don't have to specify std::basic_ifstream. I cannot find details about why typedef works this way, but the problem is reproducible. For instance,

    namespace test1
    {
    class A {
    
    public :
        static const int cn = 1;
    
        virtual ~A();
        A(int t): x(t){};
        int x;
    };
    
    class B:public A
    {
    public:
        B(int t) : A(t){};
    };
    typedef B XX;  
    };  
    class C:public test1::XX
    {
      int aaa;
        public:
    explicit  C(int x) :XX(x) // error  
    explicit  C(int x) :test1::XX(x) // ok
    explicit  C(int x) :B(x) // also ok
    {       
        aaa = A::cn;
    };
    };
    
    0 讨论(0)
  • 2021-02-13 13:19

    The difference is that ifstream isn't visible as an injected class name because it is the name of a typedef, not the name of the class. It isn't therefore visible unqualified as an injected class name from the base class.

    ios_base is a genuine class name which is a base class (of a base class) of the class where it is used and so is visible unqualified as an inject class name.

    E.g.

    namespace X
    {
        class A {};
        template<class> class Z {};
        typedef Z<char> B;
    }
    
    class C : public X::A
    {
        C() : A() {} // OK, A is visible from the base class
    };
    
    class D : public X::B
    {
        D() : B() {} // Error, B is a typedef,
        // : X::B(), : Z<char>() or even : Z() can be used.
    };
    

    In your example, instead of std::ifstream, you can use unqualified basic_ifstream instead. (Or basic_ifstream<char> or basic_ifstream<char, std::char_traits<char> > but these don't really save any typing or help clarity at all.)

    0 讨论(0)
提交回复
热议问题