Låt oss bryta ner de viktigaste skillnaderna mellan C-strukturer och C ++ klasser, och hur dessa skillnader påverkar utformningen och implementeringen av objektorienterade program i C och C ++.
C Structes vs. C ++ klasser:Nyckelskillnader
| Funktion | C Struktur | C ++ klass | Påverkan på OOP |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| Standardåtkomst | `offentligt '(medlemmar är tillgängliga som standard) | `Privat '(medlemmar är otillgängliga som standard) | Inkapsling |
| Medlemfunktioner (metoder) | Inte tillåtet direkt. Du kan simulera dem med funktionspekare. | Tillåten. Klasser kan ha metoder (funktioner) som fungerar på klassens data. | Inkapsling, beteende |
| arv | Inte stöds. | Stöds (enkel och multipel arv). | Återanvändbarhet, polymorfism |
| polymorfism | Inte direkt stödd. Kräver manuell implementering (t.ex. med funktionspekare och `void*`). | Stöds (virtuella funktioner, abstrakta klasser, gränssnitt). | Flexibilitet, utdragbarhet |
| konstruktörer/destruktorer | Inte stöds. Initialisering görs vanligtvis med tilldelning eller initialiseringsfunktioner. | Stöds. Konstruktörer initialiserar objekt, förstörare städar upp. | Resurshantering |
| Operatörsöverbelastning | Inte stöds. | Stöds. Tillåter operatörer (+, -, *, ==, etc.) att definieras för klassobjekt. | Uttrycksfullhet |
| mallar | Inte stöds. | Stöds. Möjliggör generisk programmering (skapa klasser som kan arbeta med olika datatyper). | Kodens återanvändbarhet |
| Minnesallokering | Vanligtvis används för statisk tilldelning eller stackallokering. Kan användas med dynamiskt tilldelat minne genom pekare. | Samma som strukturer. Generellt föredraget i objektsammanhang för att skapa objekt på hög för att använda polymorfism. | Minneshantering |
i detalj:
1. Åtkomstkontroll (inkapsling):
- c Struct: Alla medlemmar i en C -struktur är "offentliga" som standard. Detta innebär att alla delar av din kod direkt kan komma åt och ändra data i strukturen. Det finns inget inbyggt sätt att dölja interna data eller begränsa åtkomst.
- C ++ klasser: Standardåtkomstspecifikatorn för en C ++ -klass är "privat". Detta innebär att medlemvariabler och funktioner som standard endast är tillgängliga från klassen själv eller från sina vänklasser/funktioner. Du använder "offentliga", "skyddade" och "privata" nyckelord för att kontrollera synligheten för klassmedlemmar. Detta är avgörande för inkapsling , en av de grundläggande principerna för OOP.
2. Medlemfunktioner (metoder):
- c Struct: C Struct * kan inte * direkt innehålla funktioner (metoder) som medlemmar. För att associera funktioner med en struktur använder du vanligtvis funktionspekare som medlemmar i strukturen. Detta är en mer indirekt och mindre integrerad strategi.
- C ++ klasser: Klasser * kan * innehålla medlemsfunktioner (metoder). Dessa metoder fungerar på data i klassen och ger ett sätt att interagera med och manipulera objektets tillstånd. Detta kopplar tätt data och funktionerna som fungerar på den och förbättrar organisationen och underhållbarhet.
3. arv:
- c Struct: C Struct gör * inte * stöd arv. Du kan inte skapa en ny struktur som ärver medlemmarna i en befintlig struktur.
- C ++ klasser: C ++ klasser * gör * Stöd arv. Detta gör att du kan skapa nya klasser (härledda klasser eller underklasser) som ärver egenskaperna och beteenden hos befintliga klasser (basklasser eller superklasser). Detta främjar återanvändning av kod och gör att du kan modellera förhållanden mellan objekt (t.ex. en "hund" -klass som ärver från en "djur" -klass). Du kan också använda flera arv (ärver från flera basklasser).
4. polymorfism:
- c Struct: C -strukturer har inte direkt stöd för polymorfism (ett objekts förmåga att ta på sig många former). Du kan*simulera*polymorfism i C med hjälp av funktionspekare och `void*`, men det kräver mer manuell kodning och är mindre elegant. Du skapar i huvudsak en tabell över funktionspekare och väljer lämplig funktion som ska ringas utifrån typen av objekt.
- C ++ klasser: C ++ ger inbyggt stöd för polymorfism genom:
- virtuella funktioner: Förklaras med "Virtual" -nyckelordet i basklassen. När en virtuell funktion kallas genom en pekare eller referens till ett basklassobjekt bestäms den faktiska funktionen som körs vid körning baserat på * faktiska * typen av objektet (dynamisk sändning).
- abstrakta klasser: En klass med minst en ren virtuell funktion (deklarerad som `=0`). Abstrakta klasser kan inte instanseras direkt, men de definierar ett gränssnitt som härledda klasser måste implementera.
5. Konstruktörer och förstörare:
- c Struct: C -strukturer har inte konstruktörer eller förstörare. Initialisering görs vanligtvis genom att tilldela värden till strukturmedlemmarna efter att strukturen har deklarerats eller genom att använda initialiseringsfunktioner. Rengöring (frisläppande dynamiskt tilldelat minne) måste också göras manuellt.
- C ++ klasser: C ++ -klasser har konstruktörer (specialmedlemfunktioner som automatiskt kallas när ett objekt för klassen skapas) och förstörare (specialmedlemfunktioner som automatiskt kallas när ett objekt förstörs). Konstruktörer används för att initialisera objektets datamedlemmar, och förstörare används för att släppa alla resurser som objektet har (t.ex. dynamiskt tilldelat minne).
6. Operatörsöverbelastning:
- c Struct: Operatörsöverbelastning stöds inte i C. Du kan inte omdefiniera betydelsen av operatörer (som +, -, ==) för strukturer.
- C ++ klasser: C ++ låter dig överbelasta operatörer för klassobjekt. Detta innebär att du kan definiera vad det betyder att lägga till två objekt i din klass tillsammans, jämföra dem för jämlikhet osv. Detta kan göra din kod mer uttrycksfull och lättare att läsa.
7. mallar:
- c Struct: C har inte mallar.
- C ++ klasser: C ++ stöder mallar, som gör att du kan skriva generisk kod som kan fungera med olika datatyper utan att behöva skriva om koden för varje typ. Detta är en kraftfull funktion för återanvändning av kod.
Påverkan på designimplementering av objektorienterade program i C:
På grund av dessa begränsningar är det att skriva verkligt objektorienterade program i C * betydligt * mer utmanande och kräver en annan strategi. Du måste implementera många av de funktioner som är inbyggda i C ++ klasser. Så här kan du närma dig OOP -design i C:
1. Emulering av kapsling:
- Använd nyckelordet "statisk" för att begränsa omfattningen av variabler och funktioner till den aktuella filen. Detta ger en form av information som gömmer sig, men det är inte lika robust som C ++ 's `privata'.
- Använd namnkonventioner (t.ex. prefix "privata" medlemmar med en understreck:`_private_member`) för att indikera vilka medlemmar som är avsedda att vara interna. Detta förlitar sig på programmerare.
2. Simuleringsmetoder:
- Definiera funktioner som tar en pekare till strukturen som deras första argument ("denna" pekarekvivalent). Dessa funktioner fungerar som metoder för strukturen.
`` `c
typedef struct {
int x;
int y;
} Punkt;
void point_move (punkt *p, int dx, int dy) {// "metod" för punkt
p-> x +=dx;
p-> y +=dy;
}
`` `
3. Mimicking Arv:
- Komposition: Bädda in en struktur inom en annan struktur. Detta ger dig ett "has-a" -förhållande (t.ex. en "bil" har en "motor").
`` `c
typedef struct {
int hästkrafter;
// ...
} Motor;
typedef struct {
Motormotor; // bil * has-a * -motor
int num_wheels;
} Bil;
`` `
- "Arv" (Manual): Inkludera basstrukturen som den första medlemmen i den härledda strukturen. Detta säkerställer att Base Struct -medlemmarna läggs ut i minnet före de härledda Struct -medlemmarna. Du kan sedan kasta en pekare till den härledda strukturen till en pekare till basstrukturen (men detta kräver noggrann minneshantering och är felaktig).
`` `c
typedef struct {
int bredd;
int höjd;
} Rektangel;
typedef struct {
Rektangelbas; // "ärver" från rektangel (första medlem)
int färg;
} ColoredRectangle;
void PrintRectangleara (rektangel *rect) {
printf ("område:%d \ n", rect-> bredd * rekt-> höjd);
}
FärgedRectangle cr ={{10, 5}, 0xff0000}; // Initiera kapslad struktur
Printrectanglearea ((rektangel*) &cr); // giltigt, eftersom rektangel är först i minnet
`` `
4. faking polymorfism:
- Använd funktionspekare inom strukturen för att peka på olika implementeringar av samma funktion, baserat på objektets typ. Detta liknar strategimönstret. Du måste upprätthålla en tabell med funktionspekare.
`` `c
typedef struct form {
int x;
int y;
void (*rit) (strukturform*); // Funktionspekare för ritning
} Form;
void dragcircle (form *s) {
printf ("ritcirkel vid ( %d, %d) \ n", s-> x, s-> y);
}
void ritningsquare (form *s) {
printf ("ritning kvadrat vid ( %d, %d) \ n", s-> x, s-> y);
}
Formcirkel ={10, 20, dragcirkel};
Form kvadrat ={30, 40, ritsquare};
Circle.Draw (&Circle); // Ringer dragcirkel
fyrkant. Draw (&fyrkant); // Calls Drawsquare
`` `
5. Manuell minneshantering:
- Eftersom C -strukturer inte har konstruktörer och förstörare, måste du noggrant hantera minnesallokering och återlämnande med "Malloc" och "Free". Underlåtenhet att göra det kommer att leda till minnesläckor.
Sammanfattningsvis:
- C -strukturer är enklare datastrukturer med begränsade funktioner. De är lämpliga för situationer där du bara behöver gruppera relaterade data tillsammans.
- C ++ klasser ger kraftfulla funktioner för objektorienterad programmering, inklusive kapsling, arv, polymorfism, konstruktörer, förstörare, överbelastning av operatörer och mallar.
-Medan du * kan * implementera objektorienterade koncept i C med hjälp av strukturer, funktionspekare och manuell minneshantering, är det betydligt mer komplex, felaktig och mindre underhållbar än att använda C ++ klasser. Du implementerar i huvudsak de funktioner som C ++ tillhandahåller naturligt.
När man ska använda C -strukturer istället för C ++ -klasser
Det finns vissa situationer där att använda en C -struktur, även i ett C ++ -program, kan vara fördelaktigt:
1. Plain Old Data (POD) -typer: När du har en enkel datastruktur som bara innehåller data och inte kräver några metoder eller speciellt beteende kan en POD -struktur vara mer effektiv. En POD -struktur kan kopieras triviellt, jämföras och serialiseras utan någon speciell kod. C ++ erbjuder `std ::is_trivial` och` std ::is_standard_layout` typ drag för att avgöra om en typ har dessa egenskaper.
2. interoperabilitet med C -kod: Om du behöver gränssnitt med befintlig C -kod är det ofta det enklaste sättet att använda C -strukturer. C ++ kan direkt använda C -strukturer, medan C ++ -klasser med komplexa funktioner (som konstruktörer, virtuella funktioner etc.) inte är direkt kompatibla med C.
3. Programmering/hårdvaruabstraktion med låg nivå: Vid programmering på låg nivå (t.ex. enhetsdrivare, inbäddade system) kan du behöva kontrollera minneslayouten exakt. C -strukturer ger dig mer kontroll över detta jämfört med C ++ -klasser, där kompilatorn kan lägga till dolda medlemmar (som en virtuell funktionstabellpekare).
4. Prestationskritiska sektioner: Även om moderna C ++ -kompilatorer är mycket optimerande, kan POD-strukturer ibland erbjuda en liten prestationsfördel i mycket prestationskritiska kodavsnitt eftersom de saknar den omkostnader som är förknippade med klasser (som virtuella funktionssamtal). *Men*, denna skillnad är ofta försumbar och bra C ++ -kod kan fungera lika bra, om inte bättre.
Sammanfattningsvis :
Medan C kan simulera objektorienterade principer, är C ++ utformat för att underlätta dem direkt. C ++ erbjuder kraftfulla verktyg för inkapsling, arv och polymorfism, förenkla objektorienterad design jämfört med det mer manuella tillvägagångssättet som krävs i C. Om ditt projekt drar nytta av kärnprinciperna för OOP, är C ++ det mer lämpliga valet. C-strukturer används bäst i C ++ -projekt när direkt C-kodinteraktion behövs eller när du skapar rent datacentriska strukturer.