आप C ++ में एक स्थिर वर्ग कैसे बनाते हैं? मुझे ऐसा कुछ करने में सक्षम होना चाहिए:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
मान लिया मैंने BitParser
कक्षा बनाई । BitParser
वर्ग की परिभाषा क्या दिखेगी?
आप C ++ में एक स्थिर वर्ग कैसे बनाते हैं? मुझे ऐसा कुछ करने में सक्षम होना चाहिए:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
मान लिया मैंने BitParser
कक्षा बनाई । BitParser
वर्ग की परिभाषा क्या दिखेगी?
जवाबों:
यदि आप "स्थिर" कीवर्ड को किसी वर्ग में लागू करने का एक तरीका खोज रहे हैं, जैसे आप C # उदाहरण के लिए कर सकते हैं, तो आप प्रबंधित C ++ का उपयोग किए बिना नहीं कर पाएंगे।
लेकिन आपके नमूने की झलक, आपको बस अपने BitParser ऑब्जेक्ट पर एक सार्वजनिक स्थैतिक विधि बनाने की आवश्यकता है। इस तरह:
BitParser.h
class BitParser
{
public:
static bool getBitAt(int buffer, int bitIndex);
// ...lots of great stuff
private:
// Disallow creating an instance of this object
BitParser() {}
};
BitParser.cpp
bool BitParser::getBitAt(int buffer, int bitIndex)
{
bool isBitSet = false;
// .. determine if bit is set
return isBitSet;
}
आप इस कोड का उपयोग उसी तरीके से कर सकते हैं, जिस तरह से आप अपने उदाहरण कोड में करते हैं।
उम्मीद है की वो मदद करदे! चीयर्स।
private: BitParser() {}
यह किसी को भी उदाहरण बनाने से रोकेगा।
BitParser() = delete;
हूं कि कंस्ट्रक्टर को हटाने के इरादे को ठीक से बताना बेहतर है (न कि इसे केवल छिपाना private
)।
मैट प्राइस के समाधान पर विचार करें ।
, सी ++ अर्थ विज्ञान में व्यक्त अपने कार्य डाल करने के लिए (के लिए यह क्या आप चाहते हैं, है एक नाम स्थान में एक समारोह)।
C ++ में कोई "स्थिर वर्ग" नहीं है। निकटतम अवधारणा केवल स्थिर विधियों वाला एक वर्ग होगा। उदाहरण के लिए:
// header
class MyClass
{
public :
static void myMethod() ;
} ;
// source
void MyClass::myMethod()
{
// etc.
}
लेकिन आपको याद रखना चाहिए कि जावा जैसी तरह की भाषाओं में "स्टैटिक क्लासेस" हैक होती हैं (जैसे C #) जो गैर-सदस्य फ़ंक्शंस करने में असमर्थ हैं, इसलिए उन्हें स्टैटिक विधियों के रूप में कक्षाओं के अंदर ले जाने के बजाय है।
C ++ में, जो आप वास्तव में चाहते हैं वह एक गैर-सदस्यीय फ़ंक्शन है जिसे आप एक नाम स्थान में घोषित करेंगे:
// header
namespace MyNamespace
{
void myMethod() ;
}
// source
namespace MyNamespace
{
void myMethod()
{
// etc.
}
}
C ++ में, नाम "जावा स्टैटिक मेथड" पैटर्न के लिए कक्षाओं की तुलना में अधिक शक्तिशाली है, क्योंकि:
निष्कर्ष: C ++ में जावा / सी # पैटर्न को कॉपी / पेस्ट न करें। जावा / सी # में, पैटर्न अनिवार्य है। लेकिन C ++ में, यह खराब शैली है।
स्थैतिक विधि के पक्ष में एक तर्क था क्योंकि कभी-कभी, किसी को स्थिर निजी सदस्य चर का उपयोग करने की आवश्यकता होती है।
मैं कुछ हद तक असहमत हूं, जैसा कि नीचे दिखाया गया है:
// HPP
class Foo
{
public :
void barA() ;
private :
void barB() ;
static std::string myGlobal ;
} ;
सबसे पहले, myGlobal को myGlobal कहा जाता है क्योंकि यह अभी भी एक वैश्विक निजी चर है। CPP स्रोत पर एक नज़र स्पष्ट करेगी कि:
// CPP
std::string Foo::myGlobal ; // You MUST declare it in a CPP
void Foo::barA()
{
// I can access Foo::myGlobal
}
void Foo::barB()
{
// I can access Foo::myGlobal, too
}
void barC()
{
// I CAN'T access Foo::myGlobal !!!
}
पहली नजर में, तथ्य यह है कि नि: शुल्क फ़ंक्शन बारसी फू का उपयोग नहीं कर सकता है :: myGlobal एक एनकैप्सुलेशन दृष्टिकोण से एक अच्छी बात है ... यह अच्छा है क्योंकि एचपीपी को देखने वाला कोई भी व्यक्ति (जब तक कि तोड़फोड़ का सहारा नहीं ले सकता) तक पहुंच नहीं सकता है फू :: myGlobal।
लेकिन यदि आप इसे करीब से देखते हैं, तो आप पाएंगे कि यह एक भारी गलती है: न केवल आपके निजी चर को अभी भी एचपीपी में घोषित किया जाना चाहिए (और इसलिए, निजी होने के बावजूद सभी दुनिया के लिए दृश्यमान है), लेकिन आपको घोषित करना चाहिए एक ही एचपीपी में सभी (सभी के रूप में) कार्य जो इसे एक्सेस करने के लिए अधिकृत होंगे !!!
इसलिए एक निजी स्थिर सदस्य का उपयोग करना आपकी त्वचा पर टैटू किए गए प्रेमियों की सूची के साथ नग्न होकर बाहर घूमने जैसा है: कोई भी छूने के लिए अधिकृत नहीं है, लेकिन हर कोई झांकने में सक्षम है। और बोनस: हर किसी के पास आपके निजी के साथ खेलने के लिए अधिकृत लोगों के नाम हो सकते हैं।
private
वास्तव में ...: -डॉ
बेनामी नेमस्पेस में निजी तौर पर चीजों को निजी बनाने का फायदा होगा।
सबसे पहले, एचपीपी हेडर
// HPP
namespace Foo
{
void barA() ;
}
बस यह सुनिश्चित करने के लिए कि आपने टिप्पणी की है: न तो बारबी की कोई बेकार घोषणा है और न ही मायग्लोबल। जिसका अर्थ है कि हेडर को पढ़ने वाला कोई नहीं जानता कि बार के पीछे क्या छिपा है।
फिर, CPP:
// CPP
namespace Foo
{
namespace
{
std::string myGlobal ;
void Foo::barB()
{
// I can access Foo::myGlobal
}
}
void barA()
{
// I can access myGlobal, too
}
}
void barC()
{
// I STILL CAN'T access myGlobal !!!
}
जैसा कि आप देख सकते हैं, तथाकथित "स्थिर वर्ग" घोषणा की तरह, fooA और fooB अभी भी myGlobal तक पहुंचने में सक्षम हैं। लेकिन कोई और नहीं कर सकता। और इस सीपीपी के बाहर कोई और नहीं जानता कि fooB और myGlobal भी मौजूद है!
"स्टैटिक क्लास" के विपरीत, उसकी पता पुस्तिका में उसकी त्वचा पर टैटू वाली "अनाम" नाम की पुड़िया पूरी तरह से चढ़ी हुई है , जो काफी अच्छी तरह से AFAIK से घिरा हुआ लगता है।
जब तक आपके कोड के उपयोगकर्ता सबोटर्स नहीं होते हैं (मैं आपको एक अभ्यास के रूप में बताता हूं, यह पता लगाएं कि एक सार्वजनिक वर्ग के निजी हिस्से तक पहुंच कैसे एक गंदा व्यवहार-अपरिभाषित हैक का उपयोग कर सकता है ...), क्या private
है private
, भले ही वह क्या हो private
एक हेडर में घोषित एक वर्ग के अनुभाग में दिखाई देता है ।
फिर भी, अगर आपको निजी सदस्य तक पहुंच के साथ एक और "निजी फ़ंक्शन" जोड़ने की आवश्यकता है, तो आपको अभी भी हेडर को संशोधित करके इसे पूरी दुनिया के लिए घोषित करना होगा, जो कि एक विरोधाभास है जहां तक मेरा संबंध है: यदि मैं कार्यान्वयन को बदल देता हूं मेरा कोड (CPP भाग), तो इंटरफ़ेस (HPP भाग) को बदलना नहीं चाहिए। लियोनिदास का हवाला देते हुए: " यह उत्साह है! "
जब वर्ग स्थैतिक विधियाँ वास्तव में गैर-सदस्य कार्यों वाले नाम स्थान से बेहतर होती हैं?
जब आपको समूह में एक साथ कार्य करने की आवश्यकता हो और उस समूह को खाके पर फ़ीड करें:
namespace alpha
{
void foo() ;
void bar() ;
}
struct Beta
{
static void foo() ;
static void bar() ;
};
template <typename T>
struct Gamma
{
void foobar()
{
T::foo() ;
T::bar() ;
}
};
Gamma<alpha> ga ; // compilation error
Gamma<Beta> gb ; // ok
gb.foobar() ; // ok !!!
क्योंकि, यदि कोई वर्ग एक टेम्पलेट पैरामीटर हो सकता है, तो एक नाम स्थान नहीं हो सकता है।
#define private public
हेडर में निम्न कोड जोड़ना होगा ... ^ _ ^ ...
utilities
नाम स्थान में आवश्यक मापदंडों (और अधिक नहीं) लेने वाले फ़ंक्शन में परीक्षण किए जाने के लिए कोड डालना होगा । इस तरह, इस फ़ंक्शन को यूनिट-परीक्षण किया जा सकता है, और अभी भी निजी सदस्यों तक कोई विशेष पहुंच नहीं है (जैसा कि उन्हें फ़ंक्शन कॉल में पैरामीटर के रूप में दिया गया है) ...
namespace
क्या वे आपके लिए पहुँच प्राप्त नहीं करेंगे global
, यद्यपि छिपे हुए, सदस्य? जाहिर है कि उन्हें अनुमान लगाना होगा, लेकिन जब तक आप जानबूझकर अपने कोड को नहीं मान रहे हैं, चर नाम अनुमान लगाने में बहुत आसान हैं।
आप एक नाम स्थान में एक नि: शुल्क फ़ंक्शन भी बना सकते हैं:
BitParser.h में
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex);
}
BitParser.cpp में
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex)
{
//get the bit :)
}
}
सामान्य तौर पर यह कोड लिखने का पसंदीदा तरीका होगा। जब किसी वस्तु की आवश्यकता नहीं है तो कक्षा का उपयोग न करें।
यदि आप "स्थिर" कीवर्ड को क्लास में लागू करने का एक तरीका खोज रहे हैं, जैसे आप C # उदाहरण के लिए कर सकते हैं
स्टैटिक क्लासेस सिर्फ संकलक का हाथ होता है, जो आपको किसी भी उदाहरण के तरीके / चर लिखने से रोकता है।
यदि आप किसी सामान्य तरीके को बिना किसी उदाहरण के तरीके / चर के साथ लिखते हैं, तो यह एक ही बात है, और यही आप C ++ में करेंगे
static
200 बार लिखने या काटने / चिपकाने से रोकने के लिए एक अच्छी बात होगी।
C ++ में आप एक क्लास (स्टैटिक क्लास नहीं) का स्टैटिक फंक्शन बनाना चाहते हैं।
class BitParser {
public:
...
static ... getBitAt(...) {
}
};
तब आपको बिटपर्सर :: getBitAt () का उपयोग किए बिना फ़ंक्शन को कॉल करने में सक्षम होना चाहिए, जो किसी ऑब्जेक्ट को तुरंत बताए बिना मैं वांछित परिणाम है।
क्या मैं कुछ लिख सकता हूँ static class
?
नहीं , C ++ 11 N3337 मानक ड्राफ्ट अनुलग्नक C 7.1.1 के अनुसार:
परिवर्तन: C ++ में, स्थिर या बाहरी विनिर्देशक केवल वस्तुओं या कार्यों के नाम पर ही लागू किए जा सकते हैं। इन घोषणाओं के साथ प्रकारों का उपयोग करना C ++ में अवैध है। सी में, इन घोषणाओं को नजरअंदाज कर दिया जाता है जब प्रकार की घोषणाओं पर उपयोग किया जाता है। उदाहरण:
static struct S { // valid C, invalid in C++ int i; };
Rationale: भंडारण वर्ग के विनिर्माताओं के पास किसी प्रकार से जुड़े होने का कोई अर्थ नहीं है। C ++ में, क्लास मेंबर्स को स्टैटिक स्टोरेज क्लास स्पेसियर के साथ घोषित किया जा सकता है। प्रकार की घोषणाओं पर भंडारण वर्ग निर्दिष्ट करना उपयोगकर्ताओं के लिए भ्रमित करने वाले कोड को प्रस्तुत कर सकता है।
और जैसे struct
, class
एक प्रकार की घोषणा भी है।
एनेक्स ए में वाक्य रचना के पेड़ पर चलने से भी ऐसा ही किया जा सकता है।
यह ध्यान रखना दिलचस्प है कि static struct
सी में कानूनी था, लेकिन इसका कोई प्रभाव नहीं था: सी प्रोग्रामिंग में स्थिर संरचनाओं का उपयोग क्यों और कब करना है?
जैसा कि यहां बताया गया है, सी ++ में इसे प्राप्त करने का एक बेहतर तरीका नामस्थान का उपयोग हो सकता है। लेकिन चूंकि किसी ने भी final
यहां कीवर्ड का उल्लेख नहीं किया है, इसलिए मैं पोस्ट कर रहा हूं कि static class
C # से एक सीधा समतुल्य C ++ 11 या बाद में कैसा दिखेगा:
class BitParser final
{
public:
BitParser() = delete;
static bool GetBitAt(int buffer, int pos);
};
bool BitParser::GetBitAt(int buffer, int pos)
{
// your code
}
आपके पास C ++ में एक स्थिर वर्ग हो सकता है, जैसा कि पहले उल्लेख किया गया है, एक स्थिर वर्ग वह है जिसमें इसकी कोई भी वस्तु त्वरित नहीं है। C ++ में, यह कंस्ट्रक्टर / विध्वंसक को निजी घोषित करके प्राप्त किया जा सकता है। अंतिम परिणाम समान है।
यह C ++ में करने के C # तरीके के समान है
C # file.cs में आप किसी सार्वजनिक फ़ंक्शन के अंदर निजी संस्करण रख सकते हैं। जब किसी अन्य फ़ाइल में आप फ़ंक्शन के साथ नेमस्पेस कॉल करके इसका उपयोग कर सकते हैं:
MyNamespace.Function(blah);
यहाँ C ++ में समान कैसे लागू करें:
SharedModule.h
class TheDataToBeHidden
{
public:
static int _var1;
static int _var2;
};
namespace SharedData
{
void SetError(const char *Message, const char *Title);
void DisplayError(void);
}
SharedModule.cpp
//Init the data (Link error if not done)
int TheDataToBeHidden::_var1 = 0;
int TheDataToBeHidden::_var2 = 0;
//Implement the namespace
namespace SharedData
{
void SetError(const char *Message, const char *Title)
{
//blah using TheDataToBeHidden::_var1, etc
}
void DisplayError(void)
{
//blah
}
}
OtherFile.h
#include "SharedModule.h"
OtherFile.cpp
//Call the functions using the hidden variables
SharedData::SetError("Hello", "World");
SharedData::DisplayError();
अन्य प्रबंधित प्रोग्रामिंग भाषा के विपरीत, "स्थिर वर्ग" का C ++ में कोई अर्थ नहीं है। आप स्थैतिक सदस्य फ़ंक्शन का उपयोग कर सकते हैं।
एक मामला जहां नाम स्थान "स्थिर वर्गों" को प्राप्त करने के लिए इतना उपयोगी नहीं हो सकता है, जब इन वर्गों का उपयोग वंशानुक्रम पर रचना को प्राप्त करने के लिए किया जाता है। नाम स्थान वर्गों के मित्र नहीं हो सकते हैं और इसलिए किसी वर्ग के निजी सदस्यों तक नहीं पहुंच सकते हैं।
class Class {
public:
void foo() { Static::bar(*this); }
private:
int member{0};
friend class Static;
};
class Static {
public:
template <typename T>
static void bar(T& t) {
t.member = 1;
}
};
एक (कई में से) वैकल्पिक, लेकिन सबसे (मेरी राय में) सुरुचिपूर्ण (स्थैतिक व्यवहार का अनुकरण करने के लिए नामस्थान और निजी निर्माणकर्ताओं का उपयोग करने की तुलना में), C ++ में "वर्ग जो तात्कालिक नहीं हो सकता" व्यवहार को प्राप्त करने का तरीका होगा। private
पहुँच संशोधक के साथ एक डमी शुद्ध आभासी फ़ंक्शन की घोषणा करें ।
class Foo {
public:
static int someMethod(int someArg);
private:
virtual void __dummy() = 0;
};
यदि आप C ++ 11 का उपयोग कर रहे हैं, तो आप यह सुनिश्चित करने के लिए अतिरिक्त मील जा सकते हैं कि final
वर्ग की घोषणा में विशुद्ध रूप से (किसी स्थिर वर्ग के व्यवहार का अनुकरण करने के लिए) वर्ग की घोषणा में विनिर्देशक का उपयोग करके अन्य वर्गों को विरासत से प्रतिबंधित कर दिया जाए। ।
// C++11 ONLY
class Foo final {
public:
static int someMethod(int someArg);
private:
virtual void __dummy() = 0;
};
जैसा कि मूर्खतापूर्ण और अतार्किक लग सकता है, C ++ 11 एक "शुद्ध आभासी फ़ंक्शन जिसे ओवरराइड नहीं किया जा सकता है" की घोषणा की अनुमति देता है, जिसका उपयोग आप कक्षा final
को पूरी तरह से घोषित करने के साथ-साथ स्थैतिक व्यवहार को पूरी तरह से लागू कर सकते हैं क्योंकि यह परिणामी है। किसी भी तरह से अतिरंजित नहीं होने के लिए वर्ग और अंतर्निहित कार्य नहीं किया जाना चाहिए।
// C++11 ONLY
class Foo final {
public:
static int someMethod(int someArg);
private:
// Other private declarations
virtual void __dummy() = 0 final;
}; // Foo now exhibits all the properties of a static class