Jump to content

C++ Builder klasu objektu kopesana


nemirst
 Share

Recommended Posts

Vai nav iespejams nokopet vienas klases objektu uz tas pasas klases citu objektu, ja si klase satur String mainigos, kuriem izmers tiek nodefinets runtaimaa? Neskaitot metodes, kad atseviski katram memberim pieskir otra objekta attieciga membera vertibu.. Ja man ir statiska izmera memberi saja klase, tad parkopeju objektus viegli ar memcpy - memcpy(&obj2, &obj1, sizeof(obj1)). Pagaidam nekadas kludas sadi nemet..Vai ta drikst vispar darit?

 

Savukart, ja ir kads AnsiStrings ka klases memberis, tad verot ciet formu izmet access violation.

 

Edit: Ka kludu saskatu kaut vai to, ka sizeof, kura tiek lietota prieks memcpy, nespej noteikt pareizu klases izmeru..

Link to comment
Share on other sites

Ar memcpy nebūs vis labi tā darīt. Redz, AnsiString klasei iekšā kaut kur ir privāts mainīgais ar tipu char *, kurš reāli satur pašu stringu. Ja Tu tagad kopē savu objektu ar memcpy, tad Tu reāli uztaisi otru AnsiString objektu, kura pointeris norāda uz to pašu atmiņu. Kad viens no šiem objektiem tiek iznīcināts, tiek izsaukts viņa AnsiString'a destruktors, kurš atbrīvo atmiņu ar stringu. Diemžēl Tevis veidotajai kopijai joprojām ir pointeris uz atbrīvoto atmiņu. Jebkāda turpmāka operācija (t.sk. vēlreiz atbrīvošana) izsauc Exception.

Link to comment
Share on other sites

Gudri gan un ari ideala atbilde, diez vai butu kaut ko tadu kaut kad izdomajis. Varbut ir kada funkcija speciala, kas skatas, vai satura ir AnsiString un tad nokope to AnsiStringa char virki jauna atminas vieta un saglaba jaunu pointeri uz so vietu jaunaja objekta?

Link to comment
Share on other sites

Šis vēl ir vienkāršais gadījums. Interesantās lietas sākas tad, kad kompilators kaut kur taisa implicit temporary objektus, kuriem veic memberwise-copy. Piemēram, kad funkcija atgriež objektu. Tad šitādus arī var dabūt uz velna paraušanu, un ilgi nesaprast, kur joks. Tāpēc vislabāk visur ir padot/atgriezt pointerus vai references uz objektiem.

 

Tavā gadījumā tāda funkcija vis nebūs. Pareizais variants būtu taisīt kaut kādu metodi Clone(), kura uztaisītu jaunu objektu un piešķirtu viņa mainīgajiem tādas pašas vērtības kā eksistējošajam objektam. Tikai, protams, kopijas, kuras neitekmētu oriģinālā objekta izdzēšana.

 

Varbūt pat vēl labāk un drošāk ir taisīt copy-constructor. Tas ir konstruktors aptuveni šādā formā:

class MyClass

public:
	MyClass( MyClass &Original ) // Copy-constructor
	{
	}
};

Ja tāds būs definēts, tad arī kompilators to izmantos defaultā memberwise-copy vietā. Tiesa - es nezinu, vai šī gadījumā nav tikai MSVC++ fīča. Ceru, ka tas ir standarts, un to lieto visi kompilatori. :p

Link to comment
Share on other sites

(labots)

Ja lietotu sadu copy contructor, tad tam vajadzetu iekopet vertibas, uz kuriem rada pointeri, jauna atminas vieta?

 

class cConfig
{
  public:
  AnsiString a1, a2, a3;

  cConfig()
  {
  }

  cConfig(cConfig& Original)
 {
				   Original.a1 = a1;
					   Original.a2 = a2;
					   Original.a3 = a3;
					   // ari sadi nav izmainu
 }
}

fManaFunkcija()
{
  cConfig config1;

  config1.a1 = "aaaaaaaaa";
  config1.a2 = "bbbbbbbbbbb";
  config1.a3 = "ccccccccccccs";
  cConfig config2(config1);
  // talak izvada objektu memberus
}

 

Nezinu, ka pareizi jadara, bet sadi nekas netiek iekopets.

Labots - nemirst
Link to comment
Share on other sites

Jā. Nu, protams, ja Tu tajā konstruktorā pats ierakstīsi iekšā:

cConfig(cConfig& Original)
{
this.a1 = Original.a1;
this.a2 = Original.a2;
this.a3 = Original.a3;
}

Vai kaut kā tā - nezinu, kā no viena AnsiString var otru dabūt. :p

Labots - Vilx-
Link to comment
Share on other sites

Oi, pats nedaudz saputrojos. Ja, sadi viss iet...

 

Paldies, perfekts risinajums mana gadijuma.

 

nu vienigais, saprotams, vajag lietot indirectional operatoru aiztiekot this memberus. par cik this ir pointers.

tatad pareizi:

  this->a1;

Link to comment
Share on other sites

Ai, jā. Es C++ neesmu jau VVZ cik sen aizticis. Ikdienā kodēju C#, bet tur ir tikai punkts. :p

Link to comment
Share on other sites

Copy-konstruktoriem pieņemts argumentu padot kā const:

cConfig(const cConfig& Original)
{
...

 

Tādējādi kompilators tev uzreiz kompilēšanas laikā teiktu kļūdu, kad tu mēģinātu tam Original objektam mainīt vērtības.

Labots - bubu
Link to comment
Share on other sites

(labots)

Kas notiek, ja izveidoju klasu objektu masivu. Sakuma ar defaulto konstruktoru. Bet pec tam gribu, teiksim, masiva 1. elementaa iekopet 2. elementa objekta vertibas. To laikam nevar nekadigi ar copy constructor, ne? Neesmu ar klasem neko darbojies praktiski, tapec varbut jautajums mulkigi skan.

Kaut kur galva palicis, ka vareja pats savus operatorus veidot klasei. Teiksim '=', kurs, iespejams, varetu pie pareizas programmesanas inicializet objekta vertibas ar rhs objekta vertibam. Tad ka to labak realizet? Der varianti gan ar copy constructor(ieteicams), gan ar operatoru. Ja vispar kads no siem ir iespejams..

 

EDIT: Ja, mazliet saputrojos. Jo nav iespejams izsaukt konstuktoru uz jau izveidotu objektu.

Var noteikti taisit klases funkciju, kura iekope tas memberos, parametraa padotaa, tas pasas klases objekta memberus. Tad laikam atliek 2 varianti - klases funkcija vai savs operators..

 

Laikam tad ari jautajumu nav. Varbut kadam tikai ir savs viedoklis, kuru labprat uzklausitu.

Labots - nemirst
Link to comment
Share on other sites

IMHO nāksies pārdefinēt vienādības zīmes operatoru. Bet domāju, ka nebūtu grūti uztaisīt tā, ka gan copy-constructor, gan vienādības zīmes operators izmanto vienu un to pašu kodu.

Link to comment
Share on other sites

Ja es uztaisisu overloaded asignment operatoru, tad man nemaz nevajadzes copy constructor.

 

Luk ari kods. Tiesi tads pats ka copy konstruktoram, tikai ar atgriezamo vertibu.

  cConfig& operator=(const cConfig& rhs)
  {
  this->a1 = rhs.a1;
  this->a2 = rhs.a2;
  this->a3 = rhs.a3;
  return *this;
  }

Link to comment
Share on other sites

Nē, nu, es vienkārši domāju, ka Tu vari uztaisīt trešo funkciju

private: void Assign(const cConfig Source, cConfig Target)
{
}

kuru tālāk izmantotu gan operators gan konstruktors.

Link to comment
Share on other sites

(labots)

Ja, varu gan, bet man tas nav vajadzigs. Par cik objektu masivu sakuma izveidosu ar default konstruktoru. Un pec tam dazviet vajadzes pieskirt vienam objektam cita objekta vertibas. Tava Assign funkcija nebutu jalieto references vai pointeri, lai atgrieztu vertibu? Vai ari tu vienkarsi nedomajot uzraktiji uzmetumu? Vai ari es atkal kaut ko nesaprotu..

Labots - nemirst
Link to comment
Share on other sites

private:
void Assign(const cConfig &Source)
{
	this->a1 = Source.a1;
	this->a2 = Source.a2;
					this->a3 = Source.a3;
}
public:

cConfig& operator=(const cConfig& rhs)
{
	Assign(rhs);
	return *this;
}

cConfig(const cConfig &source)
{
	Assign(source);
}

Ideja tāda, ka, ja Tavam objektam nāks vēl klāt lauki, tad mainīt vajadzēs tikai vienā vietā. Tāpat arī visi bugi, saistīti ar šo piešķiršanu, būs jālabo tikai vienā vietā.

Labots - Vilx-
Link to comment
Share on other sites

Nu ja, es saprotu, bet man neatkartojas kods, jo vienkarsi nevajag lietot copy construktoru, ja ir izveidots savs assignment operators. Definejot kadu objektu man nekur nevajag vinu inicializet ar cita objekta vertibam. Un tagad ari redzu, ka pareizi tava funkcija nodod parametru.

Link to comment
Share on other sites

Copy konstruktors ir noderīgs jebkurā gadījumā. Piemēram:

void SomeFunction (cConfig Objekc)
{
}

Kad šādai funkcija padod kādu objektu, tad kompilators vai nu veic memberwise-copy, vai arī izmanto copy-constructor. Kad funkcija darbu beidz, tiek izsaukts destruktors. Ja Tev nav copy-constructor, vari nonākt pie tādas pašas problēmas, ar kādu sāki šo topiku. Protams, AnsiString laikam jau arī ir pārlādēts piešķiršanas operators, tāpēc arī problēmas nebūs. Bet, ja pats glabāsi kaut kādus pointerus, tad var būt kirdikc.

 

Starp citu - tagad tikai iedomājos - Tavs pārlādētais piešķiršanas operators taču sakrīt mats-matā ar defaulto memberwise-copy piešķiršanas operatoru! Kāpēc vispār taisīt problēmas un pārlādēt?

Link to comment
Share on other sites

(labots)

Lai varetu pieskirt smuki ar '=' zimi :) Nu, ja, tu parliecinaji, labak tomer uztaisisu copy constructoru un ari pieskirsanas funkciju.

 

Starpcitu, apsveicu ar 4000. postu!

Labots - nemirst
Link to comment
Share on other sites

Ieteiktu atcerēties, ka C++ kompilētājs jebkurai klasi un struktūrai pēc noklusējuma (ja vien tu pats neesi tādas norādījis) izveido trīs metodes - defaulto konstruktoru (bez argumentiem), copy-konstruktoru un piešķiršanas operatoru (kā arī, protams, defaulto destruktoru). Tas gan tādā gadījumā, ja visiem tā memberu tipiem arī eksistē atbilstošie konstruktori/piešķiršanas-operatori.

 

Šī defaultā rīcība ne vienmēr ir vēlama, īpaši jau pointeru memberu gadījumā. Tādā gadījumā ir divi varianti. Viens ir implementēt pašam šīs metodes (kā tavā gadījumā). Otrs ir aizliegt tās izmantot, lai netīšām kompilators neuzģenerētu nepareizu kodu, piemēram, izsaucot copy-konstruktoru, kad tu to nemaz nevēlējies (piemēram aizmirsi referenci kodā uzrakstī).

 

To dara padarot atbilstošās metodes privātas bez metožu implementācijas. Piemēram:

class Foobar
{
public:
Foobar() { ... }
void someMethod() { ... }
...

private:
Foobar(const Foobar&);
Foobar& operator = (const Foobar&);
};

 

Šāda rīcība padarīs tavu kodu drošāku pret netīšu kļūdu. Skat, piemēram uz šādu kodu:

Foobar a;
Foobar b = a;

Šāds kods otrajā rindiņā ģenerēs kompilēšanas laika kļūdu, ka operator = ir privāts (tb aizliegts). Tas ir ļoti labi, jo developeris bij vienkārši nokļūdījies otrā rindā, kurai bija jāizskatās:

Foobar& b = a;

 

Bez šī veida, kad metodes padara par privātām, kompilators būtu nokompilējis otro rindiņu ar, iespējams, nepareizi darbojošos kodu (kā tavā gadījumā ar tiem AnsiString).

Link to comment
Share on other sites

Jā, labi, šis man noderēs.

 

Kad implementeju sava klase savu copy-constructoru, izmeginaju neieklaut klasee savu konstruktoru(t.i. neaizvietot defaulto konstruktoru). Ja meginu nodefinet kadu klases objektu, lietojot defaulto konstruktoru, kompilers izmet kludu, noradidams, ka mana definicija neatbilst klases konstruktoram(mana gadijuma ir tikai viens konstruktors - copy constructor). Tatad iznak, ka, ja veidoju savu copy-konstruktoru, defaultais konstruktors netiek veidots. Ceru, ka tas pats neattiecas uz defaulto destruktoru. Par cik vinu neesmu implementejis. Vai objekts tiks izdzests, kad tas bus pieejams atkritumu savacejam, vai ari destruktors taa ari netiks izsaukts, ja lieto savu copy konstruktoru, nelietojot savu destruktoru?

 

Laikam tomer tiek izsaukt, par cik Buildera code completition uzradija objektam iespeju izsaukt destruktoru, kurs gan netiek uzradits parastaja class view.

Link to comment
Share on other sites

Pirmkārt - C++ nav tāda atkritumu savācēja. Tur ir strikti definēti likumi, kuros brīžos objektu jāizmet.

 

Otrkārt - tāds defaultais destruktors nekad nav bijis. :) Bet, ja objektam tāds būs definēts, tad tas tiks izsaukts arī tad, ja objekts būs veidots ar copy-constructor. Copy-constructor jau ir tāds pats konstruktors kā visi citi. Vienīgā atšķirība, ka kompilators māk viņu automātiski pielietot dažās situācijās.

Link to comment
Share on other sites

Ir kaut kada jega klasee izveidot sadu destruktoru?

~ManaKlase()
{

}

 

Otrkārt - tāds defaultais destruktors nekad nav bijis. :)

Un so te atradu C++ manualii:

The Default Destructor
All the objects that we have been using up to now have been destroyed automatically by the default destructor for the class. This is generated by the compiler in the absence of any explicit destructor being provided with a class. The default destructor doesn't delete objects or object members that have been allocated in the free store by the operator new.

Kam ticet? :)

Link to comment
Share on other sites

barakuda

Defaultais konstruktors = mantotais konstruktors.

Jebkurš objekts, pat tad ja tu nenorādi, ka tas no kaut kā manto, manto no TObject.

Ar domu, ja tu pats nekādus jaunus dinamisko memberus netaisi, atmiņu nerezervē, tad specifisks destruktors tev nav vajadzīgs.

Labots - barakuda
Link to comment
Share on other sites

Ari visi ansistringi, ja vien tie nav rezerverti, teiksim, dinamiska masiva, tiks izdzesti, ja?

Link to comment
Share on other sites

Brr, zini, es jau pats sāku apjukt. Iesaku paņemt sava kompilatora manuāli un palasīt par "Object lifecycle". Tur būs sīki un smalki apstāstīts, kad kas kā un kāpēc. :p

Link to comment
Share on other sites

Neko pratigu nevaru atrast. Skiet, ka, noteikti, automatiski netiek atbrivoti tikai tie objekti, kuri raditi ar new, alloc, t.i. memory allocation funkcijam. Ari AnsiString izmanto ko lidzigu, tacu domaju, ka Builders noteikti parupejas, ka atmina tiek atbrivota tiklidz objekts iziet arpus scope, ari, ja AnsiString ir ka manas klases memberis.

Link to comment
Share on other sites

barakuda

Builderim AnsiStrings tiek apstrādāts automātiski, par to tev nav jāuztraucas, kamēr vien tu viņus pats neieliec kaut kādā dinamiskajā objektā (kas tev pašam gan ir jānīdē ārā).

Faktiski viss ir vienkārši - saskaiti, cik tev ir new, tikpat tev jābūt arī delete vai Free (nemaz vairs neatceros, vai Builderis ņēma to Free pretī, es katrā ziņā lietoju delete).

Link to comment
Share on other sites

Jebkurš objekts, pat tad ja tu nenorādi, ka tas no kaut kā manto, manto no TObject.

Tas nu gan ir aplami. C++'ā tā nenotiek. Tur nav nekāda TObject. Ja kautkāda vide (piemēram BC++ builderis) piedāvā tādu objektu, tad tas tev pašam jānorāda, ka gribi to mantot:

class KlaseKuraMantoTObjectu : public TObject
{
  ...
};

 

Ja rakstīsi:

class ManaKlase
{
  ...
};

Tad ManaKlase nemantosies no nevienas klases.

 

Par tiem defaultajiem konstrukoriem:

C++ automātiski katrai klasei taisa: defaulto konstruktoru (konstruktors bez argumentiem), copy-konstruktors (konstruktors ar sava tipa klases const & argumentu), piešķiršanas operatoru (T& operator = (const T&)) un destruktoru.

 

Šīs četras īpašās metodes tas taisa tikai tad, ja tu pats nenorādi tādu savai klasei. T.i. - līdzko norādīsi savu konstruktoru, tā defaultais konstrukors vairs netaisīties (taču taisīties pārējās trešās īpašās metodes). Un tāpat ar citām metodēm.

 

Ir gadījumi, kad C++ automātiski nevar uzģēnerēt kādu no šīm metodēm. Piemēram, sekojošā gadījumā klasei A netiks uztaisīts defaultais konstruktors, copy-konstruktors un piešķiršānas operators:

class A
{
 int& x;
};

Tas ir tāpēc, ka references ir vienmēr jāinicializē ar kautko, bet pēc noklusējuma kompilators nezin ar ko tās inicializēt. Tāpēc tev pašam jāraksta vajadzīgie konstruktori. Destruktors gan šai klasei uzģenerēseis automātiski.

 

Pēc noklusējuma defaultais konstruktors inicializē visus ne-POD veida memberus ar to defaultajiem konstruktoriem. POD (plain-old-datatype) tipus (int/float/char/pointeri/...) konstruktors neaiztiek - tie saturēs neinicializētas vērtības.

 

Pēc noklusējuma copy-konstruktors inicializēs visus klases memberus ar argumentā padotā objekta attiecīgajiem memberiem. Līdzīgi darīs piešķiršanas operators, tikai tas nevis inicializēs memberus, bet tiem piešķirs attiecīgās vērtības.

 

Un destruktors pēc noklusējuma izsauks visu memberu destruktorus.

 

Ja klase mantojās no kādām citām klasēm, tad viss paliek drusku sarežģītāk un vēl jāņem vērā bāzes klašu konstruktors/destruktori.

 

Par to AnsiStringu (līdzīgi kā std::string, std::vector, u.c.) - tas, visdrīzāk, izmanto dinamisko atmiņu, kuru izdala vai nu konstrukotrā vai arī kādās metodēs. Taču 100%, ka tas savu atmiņu atbrīvo savā destruktorā. Tāpēc, ja lietosi šo AnsiStringu kā klases memberu, tad kompilators garantēs, ka tavas klases destruktors vienmēr izsauks visu memberu destruktorus - respektīvi, izsauks AnsiString objektu destruktorus, kuri tad arī atbrīvos to dinamisko atmiņu. Par to pašam nav jārūpējas. Pat ja tu uzdefinēsi tai klasei savu destruktoru, kurā ieliksi kautkādu kodu, kompilators vienalga pēc šī destruktora beigām izsauks visu memberu destruktorus automātiski.

Labots - bubu
Link to comment
Share on other sites

(labots)

O, jauki, paldies. Šis ir arī skaidri saprotami un loģiski, tev arī ticēšu. Vēl nedaudz pamēģināšu pameklēt kaut kur par mantotām klasēm un tad, iespējams, radīsies vēl kāds jautājums.

 

Bet taas defaultas funkcijas vienalga jaraksta ir klases definicijas koda?

Piemeram:

class MyClass
{
public:
  MyClass()  // defaultais konstruktors
  {
  // seit nav neka
  }
  MyClass(const MyClass& Src)  // copy konstruktors
  {
  // seit - mainigo kopesana
  }
};

 

Builderi ir jaieklauj defaultais konstruktors klases definicijaa, ja tiek veidots copy construktors. Ja neieklausu to, bet meginasu kaut kur kodaa inicializet objektu ar so defaulto konstrukoru, tad kompileris izmetis kludu ar pazinojumu, ka nespej inicializet objektu ar defaulto konstruktoru, ja jo tads nav atrasts.

 

Par tiem defaultajiem konstrukoriem:

C++ automātiski katrai klasei taisa: defaulto konstruktoru (konstruktors bez argumentiem), copy-konstruktors (konstruktors ar sava tipa klases const & argumentu), piešķiršanas operatoru (T& operator = (const T&)) un destruktoru.

 

Šīs četras īpašās metodes tas taisa tikai tad, ja tu pats nenorādi tādu savai klasei. T.i. - līdzko norādīsi savu konstruktoru, tā defaultais konstrukors vairs netaisīties (taču taisīties pārējās trešās īpašās metodes). Un tāpat ar citām metodēm.

 

Man netiek izstradats defaultais konstruktors, ja uztaisu pats savu copy konstruktoru.

 

 

Acimredzot, copy constuktors tiek uztverts ka parasts konstruktors jeb defaulta konstruktora aizvietojums. Tacu pielauju, ka gadijuma, kad izveidoju pats savu konstruktoru bez parametriem, tomer copy kontruktors tiek generets. Vai ta?

 

Ja, copy konstruktoru gan kompileris uzgenere ari tad, ja tiek nodefinets defaultais konstruktors. Ar defaulto gan nekas tamlidzigs nenotiek.

 

Bac, tomer tiek generets defaultais konstruktors, bet objektu var inicializet tikai sadi:

cMyClass MyClass1();

T.i., lietojot iekavas.

Sads variants neietu cauri:

cMyClass MyClass1;

 

Toties, ja ierakstu klases definicija sadas rindinas...

  cMyClass()
  {
  }

... jeb, ta teikt, ierakstu defaulto konstruktoru, tad strada abi varianti.

 

Kas par huinu, kapec ta? Esmu nedaudz apjucis.

Labots - nemirst
Link to comment
Share on other sites

Builderi ir jaieklauj defaultais konstruktors klases definicijaa, ja tiek veidots copy construktors.

Nu ja tu uztasi copy-konstruktoru, tas nozīmē, ka klasei tu esi uztaisījis kautkādu konstruktoru. Ja klasei ir uztaisīts kautkāds konstruktors (vienalga ar nevienu, vienu, vai desmit argumentiem), tad C++ vairs netaisa defaulto bez-argumentu konstruktoru. Tas ir normāli, tā nav BCB vaina.

 

Tacu pielauju, ka gadijuma, kad izveidoju pats savu konstruktoru bez parametriem, tomer copy kontruktors tiek generets. Vai ta?

Jā, pareizi.

 

Bac, tomer tiek generets defaultais konstruktors, bet objektu var inicializet tikai sadi:

cMyClass MyClass1();

T.i., lietojot iekavas.

Sads variants neietu cauri:

cMyClass MyClass1;

...

Kas par huinu, kapec ta? Esmu nedaudz apjucis.

 

Pārliecinies, ka tas kods tiešām dara, ko tu gribi lai tas dara. Pirmo rindiņu daži kompilatori uztver kā funkcijas extern deklarāciju. Tb tiek deklarēta funkcija ar vārdu MyClass1, kura atgriež cMyClass klases objektu. Kompilēties ta šāds kods komplējas, tik jautājums vai tas arī linkojas kopā. Piemēram MS Visual C++ kompilators uz to rinidņu teiks warningu izskatā "warning Cxxxx: 'cMyClass MyClass1(void)': prototyped function not called (was a variable definition intended?)". Redzams, ka tas to uztvēris kā funkciju, bet arī pabrīdina lietotāju, vai varbū viņš tur nav gribējis mainīgo deklarēt.

 

Katrā ziņā neiesaku rakstīt tukšas iekavas pie klases objekta konstruktoriem.

Link to comment
Share on other sites

(labots)

Ja, tiesam kaut kas tamlidzigs. Pameginaju pieskirt vienkarsi vertibu klases memberim sadi:

  cMyClass MyClass();
  MyClass.a1 = 4;

Un pie 2. rindinas izmeta kludu. Tatad ir ka tu saki. Paldies, tas visu atrisina.

 

Man linkojas ari projekts. Varu vinu palaist vesi, ja rakstu ar tam iekavam.

Varu ari sadi izdarit:

int ManaFunkcija(void)
{
  int adfadfadkafd();  // ieprieks nedefineta funkcija ar vienalga kadu nosaukumu,
//galvenais, ka pastav tads atgriezamais tips un piebaztas funkciju iekavas
}

Tatad taa ir parastas funkcijas definesana, ko es ieprieks dariju. Un Builderis man atlauj sadus murgus veidot, nezinu ka ar citiem rikiem..

Labots - nemirst
Link to comment
Share on other sites

Kāpēc lai tie būtu murgi? Tā ir ļoti normāla rīcība - deklarēt funkcijas pirms tā vēl ir definēta.

Skat, ja tev ir a.h fails:

int funkcija();

un tev ir a.cpp fails:

#include "a.h"
int funkcija()
{
 return 1;
}

un tev ir main.cpp fails:

#include "a.h"
int main()
{
 int x= funkcija();
}

Domāju, ka tu saproti, ka šāda ir normāla rīcība C++ programmu veidošanā.

 

Bet kompilējot main.cpp failu C++ kompilators redz sekojošu failu:

int funkcija();

int main()
{
 int x= funkcija();
}

Un neko citu tas neredz! Kā redzi tur ir arī tā "dīvainā" int funkcija(); deklarācija. Un tas ir viss normāli, jo C++'ā defaultā funkciju/mainīgo redzamība ir extern.

 

Tas ka tavā gadījumā tā funkcija ir deklarēta iekš citas funkcijas ir pilnīgi nesavarīgi, jo funkcijas/mainīgos var deklarēt visādos neimspeisos/klasēs/utml.

 

Tas, ka ar iekavām raksti, tas laikam gan visu kompilēs, bet līdzko mēģināsi izsaukt funkciju, tad būs linkošanas kļūda. Tajā otrajā kodā pamēģini zemāk uzrakstīt adfadfadkafd(); tb izsaukt to funkciju. 100 punkti, ka tad dabūsi linkošanas kļūdu. Jo C++ kompilators vienkārši izmet ārā no objektfailiem neizsauktās/neizmantotās funkcijas.

Link to comment
Share on other sites

(labots)

Kāpēc lai tie būtu murgi? Tā ir ļoti normāla rīcība - deklarēt funkcijas pirms tā vēl ir definēta.

To es apzinos, protams, un tavs piemers ari to paradija.

 

Tas ka tavā gadījumā tā funkcija ir deklarēta iekš citas funkcijas ir pilnīgi nesavarīgi, jo funkcijas/mainīgos var deklarēt visādos neimspeisos/klasēs/utml.

Bet sis man nepatik. Nepatik, ka varu deklaret savu funkciju citas funkcijas kermeni. Un tas ari ir viss, kas man ar to nepatik. Kads programmetajs ir ari tada veida deklarejis savu funkciju, liekot so deklaraciju citas funkcijas kermeni? Kam tas vispar vajadzigs?

 

Tas, ka ar iekavām raksti, tas laikam gan visu kompilēs, bet līdzko mēģināsi izsaukt funkciju, tad būs linkošanas kļūda. Tajā otrajā kodā pamēģini zemāk uzrakstīt adfadfadkafd(); tb izsaukt to funkciju. 100 punkti, ka tad dabūsi linkošanas kļūdu. Jo C++ kompilators vienkārši izmet ārā no objektfailiem neizsauktās/neizmantotās funkcijas.

Tagad ir ari skaidrs, kapec pie linkosanas nekad kludas nedabuju(EDIT: Saprotams, gadijumos, kad tikai deklareju funkciju), ari tad, ja funkcija nav defineta nekur.

Labots - nemirst
Link to comment
Share on other sites

Baigais Janka

Slinkums lasīt visu palagu, bet nu... eee... nu, es esmu deklarējis funkciju citas funkcijas ķermenī! :) Esu arī programmētājs... Ja nopietni - kāpēc? - nu, piemēram, lai deklarācija nejaucās riņķī, jo tiek izsaukta tikai no šīs vienas funkcijas, kauču - kā parametrs "callback funkcija" kaut kam.

Link to comment
Share on other sites

Neliekas diez ko jedzigi. Sadi deklaretu funkciju nevaru redzet ari sava projekta funkciju saraksta.

Link to comment
Share on other sites

Kads programmetajs ir ari tada veida deklarejis savu funkciju, liekot so deklaraciju citas funkcijas kermeni? Kam tas vispar vajadzigs?

Tas ir savietojamībai ar aizvēsturiskiem kodiem, kur tā darīja. Tb sen-senos laikos C kodā tā rakstīja. C valodā nav neimspeisu, tāpēc rakstot funkciju globālajā neimspeisā tas piemēslojas. Un šāda piemēslošana ne vienmēr ir vēlama. C++'ā šo piemēslošanu atrisina ar neimspeisiem.

 

Taču funkcijas var definēt iekš citām funkcijām:

int funcA()
{
 int funcB() { return 123; }
 return funcB();
}

int funcC()
{
 int funcB() { return 444; }
 return funcB();
}

Uzmanīgi - šis kompilēsies tikai ar C kompilatoru. C++ kompilators pateiks, ka funcB definīcija nedrīkst būt iekš funkcijas.

 

Un lieta tāda - ka C kompilators nebļaus kļūdu par to, ka funcB ir definēts divas reizes šajā kompilācijas vienībā. Nezinu vai tas ir ērti, bet nu C valodā citu veidu kā vienu un to pašu lietu ar vienu vārdu definēt nav.

 

 

Ja nopietni - kāpēc? - nu, piemēram, lai deklarācija nejaucās riņķī, jo tiek izsaukta tikai no šīs vienas funkcijas, kauču - kā parametrs "callback funkcija" kaut kam.

Normāli cilvēki programmējot normālu C/C++ to dara ar parastu deklarāciju:

void callbacks();

void mana_func()
{
 ...
 callbacks();
 ...
}

void clalbacks()
{
  ...
}

Labots - bubu
Link to comment
Share on other sites

Izveido kontu, vai pieraksties esošajā, lai komentētu

Jums ir jābūt šī foruma biedram, lai varētu komentēt tēmas

Izveidot jaunu kontu

Piereģistrējies un izveido jaunu kontu, tas būs viegli!

Reģistrēt jaunu kontu

Pierakstīties

Jums jau ir konts? Pierakstieties tajā šeit!

Pierakstīties tagad!
 Share

×
×
  • Izveidot jaunu...