为什么不需要资格?

Why is no qualification necessary?

本文关键字:不需要 为什么      更新时间:2023-10-16

好的,我将发布完整的程序尽管它有一些无关的东西并且问题代码是死代码& help;

#include <iostream>
#include <fstream>
namespace detail {
    // Solution by Johannes Schaub alias litb
    // http://groups.google.com/group/comp.std.c++/browse_thread/thread/b567617bfccabcad
    template<int> struct D {};
    typedef char yes[1];
    typedef char no[2];
    template< class T, class U >
    yes& f( int, D< sizeof T(*(U*)0) >* = 0 );
    template< class T, class U >
    no& f( ... );
    template< class To, class From >
    struct IsExplicitlyConvertible
    {
        enum{ yes = (sizeof detail::f< To, From >(0) == sizeof( detail::yes ) ) };
    };
    bool const streamsSupportWindows =
        IsExplicitlyConvertible< std::ofstream, wchar_t const* >::yes;
}
class InFStream
    : public std::ifstream
{
    public:
        InFStream() {}
        explicit InFStream(
            char const* filename,
            ios_base::openmode mode = ios_base::in | ios_base::out
            )
            : std::ifstream( filename, mode )
        {}
};
int main()
{
    using namespace std;
    cout << (detail::streamsSupportWindows
        ? "Windows-enabled"
        : "Ach, no Windows support"
        ) << endl;
}

在MSVC和g++中可以很好地编译。但是在InFStream课程中,为什么我不需要符合ios_base ?或者,同样的问题,为什么我需要在构造函数初始化列表中使用ifstreamstd::限定?

不同的是,ifstream作为注入类名是不可见的,因为它是typedef的名称,而不是class的名称。因此,作为基类注入的类名,它是不可见的。

ios_base是一个真正的类名,它是使用它的类的基类(基类的基类),因此作为注入类名是不合格的。

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.
};

在您的示例中,您可以使用不限定的basic_ifstream代替std::ifstream。(或basic_ifstream<char>basic_ifstream<char, std::char_traits<char> >,但这些并不能真正节省任何输入或帮助清晰。)

关于为什么必须在构造函数的初始化项中指定std::ifstream的一些想法。我认为typedef是罪魁祸首——ifstream被定义为typedef basic_ifstream<char, char_traits<char> > ifstream;)。如果将构造函数更改为

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

也不需要指定std::basic_ifstream。我找不到typedef为什么这样工作的细节,但问题是可重复的。例如,

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;
};
};

另一个观察是ios_base::openmode工作,但ios::openmode不能:

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

我认为a1ex07已经找到了问题的关键:在这里,ios_base是一个类的名称,而ios仅仅是一个类型定义。

区别在于类的名称是该类(9/2)的成员,因此可以作为InFStream (3.4.1/7 item 1)中的类型名称查找,因为它是InFStream的基类的成员。但是有些类型定义仅仅与基类一起出现在其他命名空间中是看不到的。

当您从类中派生时,您必须指定

std::ifstream

能够在STD命名空间中找到类。

在代码中,从std::ifstream派生的类知道ifstream的一切。

继承ifstream:

ios_base -> ios -> istream -> ifstream