C ++ 'da statik bir sınıf nasıl oluşturulur? Gibi bir şey yapabilmeliyim:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
BitParser
Sınıfı oluşturduğumu varsayarsak . BitParser
Sınıf tanımı nasıl olurdu ?
C ++ 'da statik bir sınıf nasıl oluşturulur? Gibi bir şey yapabilmeliyim:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
BitParser
Sınıfı oluşturduğumu varsayarsak . BitParser
Sınıf tanımı nasıl olurdu ?
Yanıtlar:
Örneğin "C #" gibi bir sınıfa "statik" anahtar kelimesini uygulamanın bir yolunu arıyorsanız, Yönetilen C ++ kullanmadan bunu yapamazsınız.
Ancak örneğinizin görünümünde, BitParser nesneniz üzerinde genel bir statik yöntem oluşturmanız yeterlidir. Şöyle ki:
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;
}
Bu kodu, yöntemi örnek kodunuzla aynı şekilde çağırmak için kullanabilirsiniz.
Umarım yardımcı olur! Şerefe.
private: BitParser() {}
Bu, herhangi birinin örnek oluşturmasını engelleyecektir.
BitParser() = delete;
yapıcıyı kaldırma niyetini doğru bir şekilde iletmenin daha iyi olduğunu iddia ederim (sadece gizlemek değil private
).
Matt Price'ın çözümünü düşünün .
İstediğin (o için işlevini koymak, C ++ semantik olarak ifade olduğunu ise bir ad alanında bir işlev).
C ++ 'da "statik sınıf" yoktur. En yakın kavram sadece statik yöntemlere sahip bir sınıf olacaktır. Örneğin:
// header
class MyClass
{
public :
static void myMethod() ;
} ;
// source
void MyClass::myMethod()
{
// etc.
}
Ancak "statik sınıfların", üye olmayan işlevlere sahip olamayan Java benzeri dillerde (örn. C #) bilgisayar korsanları olduğunu hatırlamak zorundasınız; bu nedenle, bunları statik yöntemler olarak sınıfların içine taşımak zorundalar.
C ++ 'da, gerçekten istediğiniz bir ad alanında bildireceğiniz üye olmayan bir işlevdir:
// header
namespace MyNamespace
{
void myMethod() ;
}
// source
namespace MyNamespace
{
void myMethod()
{
// etc.
}
}
C ++ 'da, ad alanı "Java statik yöntem" deseni için sınıflardan daha güçlüdür, çünkü:
Sonuç: Java / C # 'ın desenini C ++' da kopyalamayın / yapıştırmayın. Java / C # 'da desen zorunludur. Ancak C ++ 'da kötü bir stil.
Statik yöntemin lehine bir argüman vardı, çünkü bazen statik özel üye değişkeni kullanmak gerekiyor.
Aşağıda gösterildiği gibi biraz katılmıyorum:
// HPP
class Foo
{
public :
void barA() ;
private :
void barB() ;
static std::string myGlobal ;
} ;
İlk olarak, myGlobal'a myGlobal denir, çünkü hala küresel bir özel değişkentir. CPP kaynağına bir bakış aşağıdakileri açıklığa kavuşturacaktır:
// 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 !!!
}
İlk bakışta, serbest fonksiyon barC'nin Foo :: myGlobal'a erişememesi bir kapsülleme bakış açısından iyi bir şey gibi görünüyor ... Çok iyi, çünkü HPP'ye bakan biri (sabotaj başvurmadan) erişemez foo :: myGlobal.
Ancak yakından bakarsanız, bunun muazzam bir hata olduğunu göreceksiniz: HPP'de sadece özel değişkeniniz hala ilan edilmemeli (ve özel olmasına rağmen tüm dünya tarafından görülebilir), ancak beyan etmelisiniz aynı HPP'de erişmeye yetkili tüm (TÜMÜNDEKİ gibi) işlevler !!!
Yani özel bir statik üye kullanmak, cildinize dövme yapan sevgililerinizin listesi ile çıplak bir şekilde dışarıda yürümek gibidir: Kimse dokunmaya yetkilidir, ancak herkes göz atabilir. Ve bonus: Herkes, kendi özelliğinizle oynama yetkisi olanların isimlerine sahip olabilir.
private
gerçekten ... :-D
Anonim ad alanları, işleri gerçekten özel yapma avantajına sahip olacaktır.
İlk olarak, HPP başlığı
// HPP
namespace Foo
{
void barA() ;
}
Sadece belirttiğinizden emin olmak için: barB veya myGlobal'ın işe yaramaz bir açıklaması yoktur. Bu, başlığı okuyan hiç kimsenin barA'nın arkasında neyin gizlendiğini bilmediği anlamına gelir.
Ardından, 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 !!!
}
Gördüğünüz gibi, "statik sınıf" bildirimi gibi, fooA ve fooB hala myGlobal'a erişebiliyor. Ama başka hiç kimse yapamaz. Ve bu CPP'nin dışında hiç kimse fooB ve myGlobal'ın bile var olduğunu bilmiyor!
Derisinde dövülmüş adres defteri ile çıplak yürüyen "statik sınıf" ın aksine "anonim" ad alanı tamamen giyinmiş , bu AFAIK çok daha iyi kapsüllenmiş görünüyor.
Kodunuzun kullanıcılar sabotörler sürece, ne (ben bir egzersiz olarak, bir ... kirli bir davranış-tanımlanmamış kesmek kullanarak bir kamu sınıfın özel kısmına nasıl erişebileceğini bulmak, size haber vereceğiz) private
ise private
, hatta eğer private
bir sınıfın başlıkta bildirilen bölümünde görünür .
: Eğer özel üye erişimi olan başka bir "özel işlev" eklemeniz gerekiyorsa Yine, hala ben endişeliyim kadarıyla bir paradoks başlık değiştirerek tüm dünyaya ilan etmeli Ben uygulanmasını değiştirirseniz kodum (CPP kısmı), daha sonra arayüz (HPP kısmı) değişmemelidir. Leonidas'dan alıntı: " Bu KAHRAMAN! "
Sınıflar statik yöntemler ne zaman üye olmayan işlevlere sahip ad alanlarından daha iyidir?
İşlevleri gruplandırmanız ve bu grubu bir şablona beslemeniz gerektiğinde:
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 !!!
Çünkü, sınıf şablon parametresi olabiliyorsa, ad alanları olamaz.
#define private public
başlıklara aşağıdaki kodu eklemek olacaktır ... ^ _ ^ ...
utilities
isim alanında gerekli parametreleri (ve daha fazla) alarak bir fonksiyonda test edilecek kodu koymak olacağını tahmin ediyorum . Bu şekilde, bu işlev birim test edilebilir ve özel üyelere hala özel erişimi yoktur (işlev çağrısında parametre olarak verildiği gibi) ...
namespace
isteğinize global
atlarsa, gizli de olsa üyelerinize erişemez mi? Açıkçası tahmin etmek zorunda kalacaklar, ancak kodunuzu kasıtlı olarak gizlemiyorsanız, değişken adlarını tahmin etmek oldukça kolaydır.
Ayrıca bir ad alanında ücretsiz bir işlev de oluşturabilirsiniz:
BitParser.h içinde
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex);
}
BitParser.cpp içinde
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex)
{
//get the bit :)
}
}
Genel olarak bu, kod yazmanın tercih edilen yolu olacaktır. Bir nesneye gerek olmadığında sınıf kullanmayın.
Örneğin "C #" gibi bir sınıfa "statik" anahtar kelimesini uygulamanın bir yolunu arıyorsanız
statik sınıflar sadece sizi tutan ve herhangi bir örnek yöntem / değişken yazmanızı engelleyen derleyicidir.
Herhangi bir örnek yöntemi / değişkeni olmadan normal bir sınıf yazarsanız, aynı şeydir ve C ++ ile yapacağınız şey budur
static
200 kez yazmaktan veya kesmek / yapıştırmaktan korumak için bazı derleyici el tutma iyi bir şey olacaktır.
C ++ 'da bir sınıfın statik bir işlevi (statik bir sınıf değil) oluşturmak istiyorsunuz.
class BitParser {
public:
...
static ... getBitAt(...) {
}
};
Daha sonra, istenen sonuç olduğunu düşündüğüm bir nesneyi örneklemeden BitParser :: getBitAt () işlevini kullanarak işlevi çağırabilirsiniz.
Gibi bir şey yazabilir miyim static class
?
Hayır , C ++ 11 N3337 standart taslağı Ek C 7.1.1'e göre :
Değişiklik: C ++ 'da, statik veya extern belirteçleri yalnızca nesne veya işlevlerin adlarına uygulanabilir. Bu tanımlayıcıları tür bildirimleriyle kullanmak C ++ 'da yasa dışıdır. C dilinde, tip tanımlarında kullanıldığında bu belirticiler yok sayılır. Misal:
static struct S { // valid C, invalid in C++ int i; };
Gerekçe: Depolama sınıfı belirteçlerinin bir türle ilişkilendirildiğinde hiçbir anlamı yoktur. C ++ 'da, sınıf üyeleri statik depolama sınıfı belirleyicisi ile bildirilebilir. Tür bildirimlerinde depolama sınıfı belirteçlerine izin vermek, kodu kullanıcılar için kafa karıştırıcı hale getirebilir.
Ve benzeri struct
, class
aynı zamanda bir tür bildirimi olduğunu.
Aynısı Ek A'daki sözdizimi ağacının yürüyüşüyle çıkarılabilir.
static struct
C'de yasal olduğunu , ancak hiçbir etkisi olmadığını belirtmek ilginçtir : C programlamasında neden ve ne zaman statik yapılar kullanılır?
Burada belirtildiği gibi, bunu C ++ ile başarmanın daha iyi bir yolu ad alanlarını kullanmak olabilir. Ancak kimse final
burada anahtar kelimeden bahsetmediği için static class
, C # 'dan doğrudan bir eşdeğerinin C ++ 11 veya sonraki sürümlerinde nasıl görüneceğini gönderiyorum :
class BitParser final
{
public:
BitParser() = delete;
static bool GetBitAt(int buffer, int pos);
};
bool BitParser::GetBitAt(int buffer, int pos)
{
// your code
}
C ++ 'da statik bir sınıfa sahip olabilirsiniz, daha önce de belirtildiği gibi, statik sınıf, herhangi bir nesnesi olmayan bir sınıftır. C ++ 'da bu, yapıcı / yıkıcı özel olarak bildirilerek elde edilebilir. Sonuç aynı.
Bu, C # 'ın C ++' da yapma şekline benzer
C # file.cs dosyasında ortak bir işlevin içinde özel değişkene sahip olabilirsiniz. Başka bir dosyadayken, aşağıdaki gibi işlevli ad alanını çağırarak kullanabilirsiniz:
MyNamespace.Function(blah);
Aynı şey C ++ 'da nasıl yapılır:
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();
Diğer yönetilen programlama dillerinden farklı olarak, "statik sınıf" ın C ++ ile anlamı yoktur. Statik üye işlevini kullanabilirsiniz.
Ad alanlarının "statik sınıflar" elde etmek için çok yararlı olmadığı bir durum, bu sınıfları kalıtım üzerinde kompozisyon elde etmek için kullanmaktır. Ad alanları sınıf arkadaşları olamaz ve bu nedenle sınıfın özel üyelerine erişemez.
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;
}
};
Bir (birçok) alternatif, ancak en çok (bence) zarif (statik davranışları taklit etmek için ad alanlarını ve özel kurucuları kullanma ile karşılaştırıldığında), C ++ 'da "somutlaştırılamayan sınıf" davranışını elde etmenin yolu private
erişim değiştirici ile kukla saf sanal işlev bildirir.
class Foo {
public:
static int someMethod(int someArg);
private:
virtual void __dummy() = 0;
};
C ++ 11 kullanıyorsanız, sınıf tanımlamasındaki final
belirteci kullanarak diğer sınıfların miras almasını kısıtlamak için sınıfın miras alınmadığından (yalnızca statik bir sınıfın davranışını taklit etmek için) fazladan yol kat edebilirsiniz. .
// C++11 ONLY
class Foo final {
public:
static int someMethod(int someArg);
private:
virtual void __dummy() = 0;
};
Göründüğü kadar aptalca ve mantıksız, C ++ 11, geçersiz kılınamayan sınıfın final
statik davranışı tamamen ve tamamen uygulamak için bildirmenin yanı sıra, geçersiz kılınamayan "saf sanal işlev" bildirilmesine izin verir hiçbir şekilde kalıtsal olmamak ve kukla işlev geçersiz kılmamak.
// 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