Hangi senaryolarda C ++ ' da struct
vs a kullanmak daha iyidir class
?
Hangi senaryolarda C ++ ' da struct
vs a kullanmak daha iyidir class
?
Yanıtlar:
C ++ 'da a class
ve a struct
arasındaki farklar , yapıların varsayılan public
üyelere ve tabanlara ve sınıfların varsayılan private
üyelere ve tabanlara sahip olmasıdır. Her iki sınıf ve yapılar bir karışımına sahip olabilir public
, protected
ve private
üyeleri miras kullanabilir ve üye işlevlerini sahip olabilir.
Herhangi bir sınıf benzeri özelliği olmayan yapıları düz-eski-veri yapıları olarak kullanmanızı ve private
veri ve üye fonksiyonları ile toplu veri yapıları olarak sınıfları kullanmanızı tavsiye ederim .
Herkesin belirttiği gibi, gerçekten sadece iki gerçek dil farkı vardır:
struct
varsayılan olarak genel erişime ve class
varsayılan olarak özel erişime sahiptir.struct
varsayılan olarak public
devralma ve class
varsayılan olarak private
devralma. (İronik olarak, C ++ 'da pek çok şeyde olduğu gibi, varsayılan değer geriye doğrudur: public
kalıtım çok daha yaygın bir seçimdir, ancak insanlar nadiren struct
" public
" anahtar kelimesini yazarken kaydetmek için nadiren bildirir .Ancak uygulamadaki gerçek fark , bir kurucu / yıkıcı ilan eden ve olmayan bir class
/ arasındadır struct
. "Düz-eski-veri" POD tipi için, sınıfın yapısını ele geçirdikten sonra artık geçerli olmayan belirli garantiler vardır. Bu ayrımı açık tutmak için, birçok kişi kasıtlı olarak sadece struct
POD türleri için s kullanır ve eğer herhangi bir yöntem ekleyeceklerse class
es'yi kullanır . Aşağıdaki iki parça arasındaki fark aksi anlamsızdır:
class X
{
public:
// ...
};
struct X
{
// ...
};
(Bu arada, "POD tipi" nin aslında ne anlama geldiği hakkında bazı iyi açıklamaları olan bir iş parçacığı: C ++ 'da POD türleri nedir? )
struct
ya class
da nesne POD olup olmadığı ile bir ilgisi yoktur veya bir kopya yapıcı / yıkıcı tanımlamak gerekip gerekmediğini. Üye işlevlerinin de POD olan bir şey üzerinde hiçbir etkisi yoktur. Yazdıklarınızı tekrar okuduğumda, başka türlü
Mevcut cevaplarda birçok yanlış anlama var.
Her ikisi de class
ve struct
bir sınıf ilan.
Evet, sınıfı bildirmek için kullandığınız anahtar kelimeye bağlı olarak, erişim değiştiren anahtar kelimelerinizi sınıf tanımı içinde yeniden düzenlemeniz gerekebilir.
Ancak, sözdiziminin ötesinde, birini diğerinden seçmenin tek nedeni kongre / stil / tercihtir.
Bazı insanlar struct
üye işlevleri olmayan sınıflar için anahtar kelimeye bağlı kalmayı severler , çünkü elde edilen tanım C'den basit bir yapıya "benziyor".
Benzer şekilde, bazı insanlar class
anahtar kelimeyi üye işlevleri ve private
verileri olan sınıflar için kullanmayı sever , çünkü üzerinde "sınıf" yazar ve bu nedenle nesne yönelimli programlama hakkındaki en sevdikleri kitaptan örneklere benzer.
Gerçek şu ki, bu tamamen size ve ekibinize bağlıdır ve programınız için tam anlamıyla bir fark yaratmayacaktır.
Aşağıdaki iki sınıf, adları dışında her şekilde kesinlikle eşdeğerdir:
struct Foo
{
int x;
};
class Bar
{
public:
int x;
};
Tekrar bildirirken anahtar kelimeleri de değiştirebilirsiniz:
class Foo;
struct Bar;
( bu, Visual Studio'nun uyumsuzluk nedeniyle oluşmasına rağmen , derleyici bunu yaptığınızda bir uyarı verecektir.)
ve aşağıdaki ifadelerin her ikisi de doğru olarak değerlendirilir:
std::is_class<Foo>::value
std::is_class<Bar>::value
Anahtar kelimeleri geçemezsiniz, ancak, not Do yeniden tanımlanması ; bunun nedeni, (tek tanım kuralı uyarınca) çeviri birimleri arasındaki çift sınıf tanımlarının "aynı token dizisinden oluşması" gerektiğidir . Bu araçlar bile alışverişi olamaz const int member;
ile int const member;
ve semantik ile ilgisi yoktur class
ya struct
.
class foo { public: ... };
ve diğerinin struct foo { ... };
"kesinlikle eşdeğer" iddiasına göre doğru olması gerekebileceğine ikna olmadım . Eksik beyanların struct foo;
ve class foo;
birbirinin yerine geçebileceği mantığına gelir . Bunlar sınıf gövdesini belirtmez ve bu nedenle erişim düzenine hiçbir şey söylemezler.
Foo
ve Bar
yine / aynı tip eşdeğerdir. " Yeniden yazarken " derken bir örnek verdim . Bunu düşünmeye gel, insanları UB'ye yönlendirmemeyi sağlamak için cevabı açıklığa kavuşturacağım
Bir sınıf yerine bir yapı kullandığım tek zaman, bir işlev çağrısında kullanmadan hemen önce bir functor bildirmek ve netlik uğruna sözdizimini en aza indirmek istiyorum. Örneğin:
struct Compare { bool operator() { ... } };
std::sort(collection.begin(), collection.end(), Compare());
Gönderen C ++ SSS Lite :
Bir yapının üyeleri ve temel sınıfları varsayılan olarak herkese açıktır, sınıfta ise varsayılan olarak özeldir. Not: Temel sınıflarınızı varsayılanlara güvenmek yerine açıkça herkese açık, gizli veya korumalı hale getirmelisiniz.
yapı ve sınıf, işlevsel olarak eşdeğerdir.
Tamam, o gıcırtılı temiz tekno konuşmasından yeterince. Duygusal olarak, çoğu geliştirici sınıf ve yapı arasında güçlü bir ayrım yapar. Bir yapı, kapsülleme veya işlevsellik yolunda çok az olan açık bir bit yığını gibi hisseder. Bir sınıf, akıllı hizmetler, güçlü bir kapsülleme engeli ve iyi tanımlanmış bir arayüzle toplumun yaşayan ve sorumlu bir üyesi gibi hissediyor. Çoğu insanın zaten sahip olduğu çağrışım olduğundan, çok az yöntemi olan ve genel verilere sahip bir sınıfınız varsa (böyle şeyler iyi tasarlanmış sistemlerde var!) Büyük olasılıkla struct anahtar sözcüğünü kullanmalısınız, aksi takdirde sınıfı kullanmalısınız anahtar kelime.
Bir yapının benim için yararlı olduğu bir yer, başka bir sistemden sabit formatlı mesajlar (örneğin bir seri port) alan bir sistemim olduğunda. Bayt akışını alanlarınızı tanımlayan bir yapıya atabilir ve ardından alanlara kolayca erişebilirsiniz.
typedef struct
{
int messageId;
int messageCounter;
int messageData;
} tMessageType;
void processMessage(unsigned char *rawMessage)
{
tMessageType *messageFields = (tMessageType *)rawMessage;
printf("MessageId is %d\n", messageFields->messageId);
}
Açıkçası, bu C ile aynı şeydir, ancak mesajı bir sınıfa deşifre etmenin yükünün genellikle buna değmediğini görüyorum.
operator >>
yerine yazılı bir sınıfına processMessage
da C yapacağı işlevi, ++ daha uygun C ++ gibi ve daha az C gibi görünüm
__packed__
yapıyı kullanmanız ve endian farkında bir ifdef uygulamasına sahip olmanız gerekir (endianess'in dış veri kaynağının ters olduğu bir makinede siparişi çevirmeniz gerekir Sağlıyor). Bu hoş değil, ancak gömülü platformlardaki uzak çevre birimleri için kayıtları taşınabilir bir şekilde paketledim / paketinden çıkarttım.
char
ad burada bir sorun olmayacak çünkü işaretçilerden biri takma isimden muaf bir tür. Bununla birlikte, yine de farklı bir sorun olsa da: char*
Farklı bir türe a dökülmesi , eğer o adreste zaten başlatılmış olan ikinci tipte herhangi bir nesne yoksa, yaşam boyu kurallarını ihlal ettiği için UB'dir. Afaik, hedef türü önemsiz bir şekilde yapılandırılabilir olsa bile, sadece ayrılmış bellek olması C ++ için bu belleğin bu tür olarak resmen işlenmesine izin vermek için yeterli değildir.
Dahili C ++ olan bir kitaplık yazıyorsanız ancak API C veya C ++ koduyla çağrılabilirse, C ++ 'da "struct" kullanabilirsiniz. Sadece hem C hem de C ++ koduna maruz bıraktığınız yapıları ve global API işlevlerini içeren tek bir üstbilgi yaparsınız:
// C access Header to a C++ library
#ifdef __cpp
extern "C" {
#endif
// Put your C struct's here
struct foo
{
...
};
// NOTE: the typedef is used because C does not automatically generate
// a typedef with the same name as a struct like C++.
typedef struct foo foo;
// Put your C API functions here
void bar(foo *fun);
#ifdef __cpp
}
#endif
Daha sonra C ++ kodunu kullanarak bir C ++ dosyasına bir işlev çubuğu () yazabilir ve C'den çağrılabilir yapabilirsiniz ve iki dünya, bildirilen yapı üzerinden veri paylaşabilir. C ve C ++ 'ı karıştırırken elbette başka uyarılar da var, ancak bu basitleştirilmiş bir örnektir.
Her birinin söylediği gibi, tek gerçek fark varsayılan erişimdir. Ancak, bazı yardımcı yöntemleri uygulasam bile, basit bir veri sınıfıyla herhangi bir kapsülleme istemediğimde özellikle yapı kullanıyorum. Örneğin, böyle bir şeye ihtiyacım olduğunda:
struct myvec {
int x;
int y;
int z;
int length() {return x+y+z;}
};
Kendi sorumu (utanmadan) cevaplamak için, Daha önce de belirtildiği gibi, erişim ayrıcalıkları C ++ 'da tek farktır.
Bir yapıyı yalnızca veri depolama için kullanma eğilimindeyim. Verilerle çalışmayı kolaylaştırırsa birkaç yardımcı işlev almasına izin vereceğim. Ancak, veri akış kontrolü gerektirdiğinde (yani dahili bir durumu koruyan veya koruyan alıcılar / ayarlayıcılar) veya herhangi bir büyük işlevselliği (temelde daha fazla nesne benzeri) elde etmeye başlar başlamaz, daha iyi iletişim kurmak için bir sınıfa 'yükseltilir'.
Yapılar ( POD'lar) , daha genel olarak), C ++ uygulamasıyla C uyumlu bir arayüz sağlarken kullanışlıdır, çünkü bunlar dil sınırları ve bağlayıcı formatları arasında taşınabilir.
Bu sizin için bir endişe değilse, o zaman "sınıf" yerine "yapı" kullanımı niyet iyi bir iletişim olduğunu varsayalım (@ZeroSignal yukarıda söylediğim gibi). Yapılar ayrıca daha öngörülebilir kopyalama semantiğine sahiptir, bu nedenle harici ortama yazmayı veya kablo üzerinden göndermeyi düşündüğünüz veriler için yararlıdır.
Yapılar, sadece bir grup bağımlı typedef'i ortaya çıkaran özellik şablonları gibi çeşitli meta programlama görevleri için de kullanışlıdır:
template <typename T> struct type_traits {
typedef T type;
typedef T::iterator_type iterator_type;
...
};
... Ama bu sadece yapının varsayılan koruma düzeyinin halka açık olmasından faydalanıyor ...
C ++ için, yapılar ve sınıflar arasında pek bir fark yoktur. Temel fonksiyonel fark, yapıların üyelerinin varsayılan olarak herkese açık olmaları ve sınıflarda varsayılan olarak gizli olmalarıdır. Aksi takdirde, dil söz konusu olduğunda, bunlar eşdeğerdir.
Bununla birlikte, Brian'ın söylediklerine benzer şekilde, C # 'da yaptığım gibi C ++' daki yapıları kullanma eğilimindeyim dedi. Yapılar basit veri kaplarıyken, sınıflar yalnızca veri üzerinde tutmanın yanı sıra veriler üzerinde hareket etmesi gereken nesneler için de kullanılır.
Onlar hemen hemen aynı şey. C ++ büyüsü sayesinde, bir yapı işlevleri tutabilir, kalıtım kullanabilir, "new" kullanarak yaratılabilir ve tıpkı bir sınıf gibi
Tek işlevsel fark, bir sınıfın özel erişim haklarıyla başlarken, bir yapı halkla başlar. Bu, C ile geriye doğru uyumluluğu korumaktır.
Uygulamada, yapıları her zaman veri sahipleri olarak ve sınıfları nesne olarak kullandım.
Diğerlerinin işaret ettiği gibi
Stroustrup / Sutter'dan ne zaman kullanılacağı hakkında net bir öneri var:
Ancak, beyanı iletmenin akıllıca olmadığını unutmayın. class ( class X;
) olarak tanımlayın ve struct ( struct X { ... }
) olarak tanımlayın . Bazı bağlayıcılarda (örn. G ++) çalışabilir ve diğerlerinde başarısız olabilir (örn. MSVC), böylece kendinizi geliştirici cehenneminde bulacaksınız.
class Foo; struct Foo { void bar() {} }; int main() { Foo().bar(); }
şey sadece MSVC 2017'yi derlemek ve çalıştırmakla kalmaz, aynı zamanda Foo
olarak struct
tanımlanan ancak olarak tanımlanmış net bir uyarı üretir class
. Ama aynı zamanda bu aptal hatayı bulmak için ekibimizin yarım güne mal olduğunu açıkça hatırlıyorum. O zamanlar hangi MSVC sürümünü kullandığımızdan emin değilim.
class
struct
struct
-forward'dan -forward'a class
geçince problemler ortadan kayboldu. Bugün itibariyle onu da garip buluyorum. Üzerine biraz ışık tutabilirseniz sevinirim.
Sınıf üyeleri varsayılan olarak gizlidir.
class test_one {
int main_one();
};
Eşittir
class test_one {
private:
int main_one();
};
Yani denersen
int two = one.main_one();
Bir hata alırız: main_one is private
çünkü erişilebilir değil. Herkese açık olarak belirterek başlatarak çözebiliriz.
class test_one {
public:
int main_one();
};
Yapı, üyelerin varsayılan olarak herkese açık olduğu bir sınıftır.
struct test_one {
int main_one;
};
main_one
Özel araçlar yani
class test_one {
public:
int main_one;
};
Üyelerin herhangi bir değer alabileceği veri yapıları için yapıları kullanıyorum, bu şekilde daha kolay.
Bir avantajı struct
üzerinde class
"o zaman özel, ilk kamu üyelerine" bağlı kalarak eğer, bir satır kodun kurtarmak olmasıdır. Bu ışık altında, anahtar kelimeyi class
işe yaramaz buluyorum.
Burada sadece kullanmak için bir başka nedendir struct
ve asla class
. C ++ için bazı kod stili yönergeleri, işlev makroları için küçük harfler kullanılmasını önerir; bunun mantığı, makro bir satır içi işleve dönüştürüldüğünde adın değiştirilmesi gerekmemesidir. Burada aynı. Güzel C tarzı yapınız var ve bir gün, bir yapıcı veya bir kolaylık yöntemi eklemeniz gerektiğini öğreniyorsunuz. Bunu birclass
? Her yerde?
Arasındaki ayrım struct
S ve class
es çok zor bir iştir, ne yapmamız gerektiğini - programlamayı - yapmaktır. C ++ 'ın birçok problemi gibi, geriye dönük uyumluluk konusundaki güçlü arzudan kaynaklanmaktadır.
class
? struct
Anahtar kelimeyle tanımlanan bir sınıfın üye işlevlerine veya bir kurucuya sahip olamayacağını mı düşündünüz ?
joe()
ile tanımlanmalıdır class
? En az 4 int
üyesi olan her sınıf struct
anahtar kelime ile mi tanımlanmalıdır ?
struct
, yöntemlerleclass
. Çok fazla güçlük.
farklı varsayılanlarla aynı şeydir (varsayılan olarak özel ve varsayılan olarak class
herkese açık struct
), bu nedenle teoride tamamen değiştirilebilirler.
yani, sadece hareket etmek için bazı bilgileri paketlemek istiyorsanız, ben orada birkaç yöntem koymak (ama çok değil) bile, bir yapı kullanın. Temel kullanımın doğrudan veri üyelerine değil, yöntemlerle olacağı çoğunlukla opak bir şeyse, tam bir sınıf kullanırım.
Hem struct
ve class
gerçi görünürlüğe gibi farklı varsayılanlarla başlık altında aynıdır, struct
varsayılan kamu ve class
varsayılan özeldir. Sen uygun kullanımı ile diğer olmak ikisinden birini değiştirebilir private
vepublic
. Her ikisi de mirasa, yöntemlere, kuruculara, yıkıcılara ve nesne yönelimli bir dilin tüm güzelliklerine izin verir.
Ancak ikisi arasındaki büyük fark, struct
anahtar kelime C olarak desteklenirken desteklenmemesidir class
. Tek bir kullanabileceği Bu araçlar struct
bir olabilir dosyası içerir #include
sürece ya C ++ veya C içine struct
düz bir C tarzı struct
ve diğer her şeyin dosyası yani hiçbir C ++ gibi spesifik anahtar kelimeler, C uyumlu dahil private
, public
hiçbir yöntemleri, kalıtım yok vb.
AC stili struct
, struct
verileri arayüz üzerinde ileri ve geri taşımak için C stilinin kullanılmasını destekleyen diğer arabirimlerle kullanılabilir .
AC stili struct
, bir bellek alanının düzenini tanımlayan bir tür şablondur (bir C ++ şablonu değil, bir desen veya şablon). Yıllar içinde C ve C eklentileri ile kullanılabilen arayüzler (burada Java ve Python ve Visual Basic'e bakıyoruz), bazıları C stili ile çalışıyor struct
.
Teknik olarak her ikisi de C ++ 'da aynıdır - örneğin, bir yapının aşırı operatörlere sahip olması mümkündür.
Ancak :
Ben aynı anda birden çok türde bilgi aktarmak istediğinizde yapıları kullanmak "işlevsel" bir nesne ile uğraşırken ben sınıfları kullanın.
Umarım yardımcı olur.
#include <string>
#include <map>
using namespace std;
struct student
{
int age;
string name;
map<string, int> grades
};
class ClassRoom
{
typedef map<string, student> student_map;
public :
student getStudentByName(string name) const
{ student_map::const_iterator m_it = students.find(name); return m_it->second; }
private :
student_map students;
};
Örneğin, burada get ... () yöntemlerinde bir yapı öğrencisi döndürüyorum - tadını çıkarın.
Struct'ı ne zaman kullanmayı ve C ++ 'da sınıfı ne zaman kullanmayı seçersiniz?
Kullandığım struct
tanımlamam zaman functors
ve POD
. Aksi takdirde kullanıyorum class
.
// '()' is public by default!
struct mycompare : public std::binary_function<int, int, bool>
{
bool operator()(int first, int second)
{ return first < second; }
};
class mycompare : public std::binary_function<int, int, bool>
{
public:
bool operator()(int first, int second)
{ return first < second; }
};
std::binary_function<>
sadece onaylanmamış değil, c ++ 17 bile kaldırıyor.
Tüm sınıf üyeleri varsayılan olarak özeldir ve tüm yapı üyeleri varsayılan olarak herkese açıktır. Sınıfın varsayılan özel tabanları ve Struct varsayılan ortak tabanları vardır. C durumunda yapı üye işlevlerine sahip olamaz, burada C ++ durumunda olduğu gibi yapıya üye işlevlerini ekleyebiliriz. Bu farklılıklar dışında, onlar hakkında şaşırtıcı bir şey bulamıyorum.
Yapıyı yalnızca ilişkili bazı üye işlevleri olmadan (üye verileri üzerinde çalışmak için) ve veri değişkenlerine doğrudan erişmek için bazı verileri tutmam gerektiğinde kullanıyorum.
Örn: Dosyalardan ve soket akışlarından veri okuma / yazma vb. Fonksiyon argümanlarının çok fazla olduğu ve fonksiyon sözdiziminin çok uzun olduğu bir yapıda fonksiyon argümanlarını iletme.
Teknik olarak, varsayılan erişilebilirlik dışında sınıf ve strütür arasında büyük bir fark yoktur. Daha fazlası programlama tarzını nasıl kullandığınıza bağlıdır.
Ben Yapılar bir Veri Yapısı (bir çok veri tipi bilgi dizisi gibi) olarak tasarlandığını ve sınıflar Kod Paketleme (alt rutin ve fonksiyon koleksiyonları gibi) için inted olduğunu düşündüm.
:(
C ++ 'da asla "struct" kullanmıyorum.
İsteyerek kafa karıştırmaya çalışmadığınız sürece, özel üyeler istediğinizde bir yapı kullanacağınız bir senaryo hayal bile edemiyorum.
Yapıları kullanmak, verilerin nasıl kullanılacağına dair sözdizimsel bir göstergedir, ancak sadece bir sınıf yapmak ve bunu sınıf adına veya yorumlarla açık hale getirmeyi tercih ederim.
Örneğin
class PublicInputData {
//data members
};
struct
Sınıf üyelerinin varsayılan olarak herkese açık olacağı konusunda açık bir açıklama yapmak istemez miydiniz ?