2011-10-23 32 views
13

Tamam, fazladan bir şey olsa bile tam bir program yayınlayacağım ve söz konusu kod ölü kod ve hellip;Neden bir yeterlilik gerekli değil?

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

Bu, MSVC ve g ++ ile iyi bir şekilde derlenir. Fakat InFStream sınıfında, neden ios_base'u nitelendirmem gerekmiyor? Ya da, aynı soru, neden yapıcı başlatıcı listesinde ifstreamstd:: kalifikasyonunu kullanmam gerekiyor?

+2

ifstream' std ad olan 'için? Neden onu kullanmanıza gerek olmadığını düşünüyorsunuz? –

+2

@ VJo: 'ios_base' ayrıca' std' ad alanındadır. Neden bu derleme derim ki derler ki bu kodu derler, çünkü onlar yaparlar. Heh. –

+4

Muhtemelen, InFStream sınıfınız std :: ios_base'den miras alınan std :: ifstream'den miras aldığından. Bu nedenle, tüm ios_base numaralandırmaları, sınıfınızın miras yoluyla üyedir ve tam bir kalifikasyona ihtiyaç duymaz. – Praetorian

cevap

6

Bazı düşünceler. Sanırım typedef suçludur - ifstreamtypedef basic_ifstream<char, char_traits<char> > ifstream; olarak tanımlanmıştır). Eğer

explicit InFStream(
    char const*   filename, 
    ios_base::openmode mode = ios_base::in | ios_base::out 

    ): 
    basic_ifstream<char,std::char_traits<char>>(filename, mode){} 

için yapıcı değiştirirseniz, ayrıca std::basic_ifstream belirtmek gerekmez. Bu şekilde neden typedef çalışır, ancak sorun yeniden üretilebilir. Örneğin,

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

temel sınıfı, hangi çözümün "çözüm" olduğu rasgele bir bit seçmem gerekiyordu, ama bence bu cevap 'typedef 'sorununu ilk işaret ediyordu. –

+0

Ve eklemek için '' basic_ifstream (dosya adı, mod) {} ​​'yazabilirsiniz. Şablon argüman listesi için gerek yok (ve gcc4.5'ten başlayarak, gcc sonunda bunu doğru olarak alır). –

0

Eğer

std::ifstream 

std ad alanında sınıf bulmak mümkün belirtmek sahip sınıfından türetmek zaman.

Kodun kendisinde std :: class sınıfından türetilen sınıf, ifstream'in herşeyi bilir. ifstream

Kalıtım: Eğer şantiye in başlatıcısı std::ifstream belirtmek zorunda neden

ios_base -> ios -> istream -> ifstream 
+0

ios_base' nedir? Ayrıca std' ad alanında da yaşıyor. –

+0

evet ama onun ifstream – Totonga

7

fark bir typedef adı değil, class adıdır için ifstream enjekte sınıf adı olarak görülmez olmasıdır. Bu nedenle, temel sınıftan enjekte edilmiş bir sınıf adı olarak nitelendirilemez.

ios_base, kullanıldığı sınıfın temel sınıfı (temel sınıfın) olan ve dolayısıyla bir sınıf içi sınıf adı olarak nitelenmemiş görünebilen orijinal bir sınıf adıdır.

E.g. Örnekte

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

yerine std::ifstream arasında, bunun yerine vasıfsız basic_ifstream kullanabilirsiniz. (Ya basic_ifstream<char> veya basic_ifstream<char, std::char_traits<char> > ama bunlar gerçekten herhangi yazmaktan kurtarır ya da hiç netlik yardım etmez.)

4

başka gözlem edilir ios_base :: openMode çalıştığını, ancak ios :: openMode yapmaz:

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

Bence a1x07 maddenin zıttı buldu: burada yine ios_base bir sınıfın adı, ios sadece bir typedef.

Ve fark, bir sınıfın adı, bu sınıfın (9/2) bir üyesidir ve bu nedenle, InFStream (3.4.1/7 madde 1) cinsinden türün adı olarak bakılabilir. InFStream taban sınıfının bir üyesidir. Ancak, bazı ad alanlarındaki bazı temel isimlerle birlikte sadece yazılanlar görülemez.

[C++ 98 Standart bölüm numaraları.]

İlgili konular