2011-10-23 18 views
13

ठीक है, मैं सिर्फ पूरा प्रोग्राम पोस्ट करूंगा, भले ही इसमें अतिरिक्त सामान हो और प्रश्न में कोड मृत कोड और नरकिप है;कोई योग्यता क्यों आवश्यक नहीं है?

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

यह एमएसवीसी और जी ++ के साथ ठीक संकलित करता है। लेकिन InFStream कक्षा में, मुझे ios_base योग्यता प्राप्त करने की आवश्यकता क्यों नहीं है? या, एक ही सवाल वास्तव में, मुझे std:: कन्स्ट्रक्टर प्रारंभकर्ता सूची में ifstream की योग्यता का उपयोग करने की आवश्यकता क्यों है?

+2

क्योंकि 'ifstream' एसटीडी नाम स्थान में है? आपको ऐसा क्यों लगता है कि आपको इसका इस्तेमाल करने की आवश्यकता नहीं है? –

+2

@VJo: 'ios_base'' std' नेमस्पेस में भी है। मुझे क्यों लगता है कि मैं जिन कंपाइलर्स का उल्लेख करता हूं, वे इस कोड को ठीक से संकलित करते हैं, ऐसा इसलिए है क्योंकि वे करते हैं। हे। –

+4

संभवतः क्योंकि आपकी इनफस्ट्रीम क्लास std :: ifstream से प्राप्त होती है जो बदले में std :: ios_base से विरासत में होती है। इसलिए सभी ios_base गणनाएं आपके वर्ग के सदस्य विरासत के माध्यम से हैं और पूर्ण योग्यता की आवश्यकता नहीं है। – Praetorian

उत्तर

6

के बारे में तुम क्यों निर्माता के प्रारंभकर्ता में 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; 
}; 
}; 
+0

के अपने आधार वर्ग मैं मनमाने ढंग से एक सा चयन करने के लिए जो जवाब है, "समाधान" था, लेकिन मुझे लगता है कि इस सवाल का जवाब 'typedef' मुद्दा बताते पहले से एक था। –

+0

और जोड़ने के लिए, आप बस 'मूल_फस्ट्रीम (फ़ाइल नाम, मोड) {} 'लिख सकते हैं। टेम्पलेट तर्क सूची की आवश्यकता नहीं है (और gcc4.5 से शुरू होता है, अंत में gcc अंततः यह सही हो जाता है)। –

0

आप वर्ग आप से निकाले जाते हैं जब

std::ifstream 

एसटीडी नाम स्थान में वर्ग को खोजने के लिए सक्षम होने के लिए निर्दिष्ट करें।

कोड में ही आप std :: ifstream से प्राप्त कक्षा को ifstream के सब कुछ जानता है। ifstream की

विरासत:

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

'ios_base' का क्या? यह 'std' नामस्थान में भी रहता है। –

+0

हाँ लेकिन ifstream – Totonga

7

अंतर यह है कि 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. 
}; 

अपने उदाहरण में, std::ifstream के बजाय, आप के बजाय अयोग्य basic_ifstream उपयोग कर सकते हैं। है (या basic_ifstream<char> या basic_ifstream<char, std::char_traits<char> > लेकिन इन वास्तव में किसी भी लेखन बच नहीं है या बिल्कुल भी स्पष्टता मदद करते हैं।)

4

एक और अवलोकन है कि 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 आइटम 1) में प्रकार के नाम के रूप में देखा जा सकता है यह InFStream की बेस क्लास का सदस्य है। लेकिन कुछ अन्य नामस्थान में केवल बेस क्लास के साथ कुछ टाइपिफ़ को देखा नहीं जा सकता है।

[C++ 98 से स्टैंडर्ड खंड संख्या।]

संबंधित मुद्दे