Jump to content

SUBIECTE NOI
« 1 / 5 »
RSS
Schimbare adresa DNS IPv4 pe rout...

Recomandare Barebone

Monede JO 2024

Suprasolicitare sistem electric
 CIV auto import

Mutare in MOZAMBIC - pareri, expe...

Scoatere antifurt airtag de pe ha...

Magnet in loc de clește pent...
 Cumparat/Locuit in apartament si ...

Pot folosi sistemul PC pe post de...

Sokol cu distorsiuni de cross-over

Filtru apa potabila cu osmoza inv...
 Kanal D va difuza serialul “...

Upgrade xiaomi mi11

securitate - acum se dau drept - ...

Farmacia Dr Max - Pareri / Sugest...
 

Chestiune interesantă în C++

- - - - -
  • Please log in to reply
13 replies to this topic

#1
Googlegps

Googlegps

    Member

  • Grup: Members
  • Posts: 242
  • Înscris: 01.11.2012
Ceva destul de straniu se întâmplă în C++ (lucru pe care nici măcar profii de facultă nu-l știu).

Să presupunem că avem (abstractizat și conceptual vorbind):
- o clasa;
- este definit un cast de la clasa respectivă la type-ul întreg (operator int() ).
- un operator+ (de adunare) pentru 2 instante ale clasei.

Fie ob - un obiect/o instantă a clasei.

In programul principal, avem:
ob+100 (scriere, whatever..) și
100+ob.

În mod normal, majoritatea compilatoarelor aruncă o eroare de ambiguitate având 2 posibilități la fel de bune:
- fie transformă obiectul ob în intreg, și face sumare obișnuită (adunare dintre 2 intregi)
- fie transformă 100 în obiect al clasei, și face sumare dintre 2 obiecte (prin operator+ definit).

Aici apare problema. Unele compilatoare accepta ob+100 dar 100+ob nu, unele (majoritatea) nu acceptă niciuna - eroare de ambiguitate, altele le acceptă pe ambele (și utilizează una din cele 2 posibilități, după ce regulă, nimeni nu știe ). Vreau să spun că aceste compilatoare se comporta diferit.

Care ar fi explicația?
Acestă temă este în discuție chiar și printre profesorii de facultate .

Edited by Googlegps, 18 April 2014 - 23:36.


#2
puya4ever

puya4ever

    Active Member

  • Grup: Members
  • Posts: 1,987
  • Înscris: 21.12.2006

View PostGooglegps, on 18 aprilie 2014 - 23:34, said:

Ceva destul de straniu se întâmplă în C++ (lucru pe care nici măcar profii de facultă nu-l știu).

Să presupunem că avem (abstractizat și conceptual vorbind):
- o clasa;
- este definit un cast de la clasa respectivă la type-ul întreg (operator int() ).
- un operator+ (de adunare) pentru 2 instante ale clasei.

Fie ob - un obiect/o instantă a clasei.

In programul principal, avem:
ob+100 (scriere, whatever..) și
100+ob.

În mod normal, majoritatea compilatoarelor aruncă o eroare de ambiguitate având 2 posibilități la fel de bune:
- fie transformă obiectul ob în intreg, și face sumare obișnuită (adunare dintre 2 intregi)
- fie transformă 100 în obiect al clasei, și face sumare dintre 2 obiecte (prin operator+ definit).

Aici apare problema. Unele compilatoare accepta ob+100 dar 100+ob nu, unele (majoritatea) nu acceptă niciuna - eroare de ambiguitate, altele le acceptă pe ambele (și utilizează una din cele 2 posibilități, după ce regulă, nimeni nu știe ). Vreau să spun că aceste compilatoare se comporta diferit.

Care ar fi explicația?
Acestă temă este în discuție chiar și printre profesorii de facultate .

Regula dupa care compilatoarele fac handle diferit la chestia asta mi
se pare irelevanta. Pur si simplu au implementari diferite, si deci
un behaviour diferit. Nu mi se pare o chestie atat de semnificativa
incat sa fi fost nevoie sa fie standardizata.

In lumea reala, atunci cand te lovesti de astfel de cod, ceva clar pute,
insa nu despre asta discutam.

Normal, intr-un limbaj strong-typed, cum e C++ mi s-ar parea sa nu
accepte nici una din variante, asa cum ai spus si tu.

edit: compilatoarele care dau eroare, nu fac cast automat in momentul
in care se face adunarea, de la tipul clasei la intreg, altele fac, doar
pe jumatete...

Edited by puya4ever, 18 April 2014 - 23:56.


#3
potae

potae

    Sorosist frumos si liber

  • Grup: Senior Members
  • Posts: 3,429
  • Înscris: 20.08.2013
Cum a zis si puya, depinde de implementarea fiecarui compilator. Si in Visual Studio esti lasat sa incluzi stdio.h si teoretic sa lucrezi in C insa accepta functii cu parametru &referinta sau nu stie de popen ci de _popen...

Insa altceva mi-a atras mie atentia :naughty:

View PostGooglegps, on 18 aprilie 2014 - 23:34, said:

Ceva destul de straniu se întâmplă în C++ (lucru pe care nici măcar profii de facultă nu-l știu).
Crezi ca daca ii ducea un picut mai mult capu' mai erau profesori de facultate? In cv-ul multora daca te uiti au fix 0 experienta reala. Dupa absolvire s-au bagat direct preparatori... si e valabil pt.majoritatea profesorilor universitari din romania din pacate.

View PostGooglegps, on 18 aprilie 2014 - 23:34, said:

Acestă temă este în discuție chiar și printre profesorii de facultate .
Sunt convins ca abia dorm aia noaptea din cauza asta. Se gandesc de vreo 3-4 ori pe saptamana la chestiune :)).

#4
Isaak

Isaak

    Member

  • Grup: Members
  • Posts: 459
  • Înscris: 08.06.2011
Aici apare problema. Unele compilatoare accepta ob+100 dar 100+ob nu, unele (majoritatea) nu acceptă niciuna - eroare de ambiguitate, altele le acceptă pe ambele

E normal sa dea eroare intr-un astfel de caz. C++ -ul are niste reguli clare care trebuie respectate de orice compilator.Acele compilatoare care nu dau eroare au fost implementate gresit. Visual Studio e ok din punctul asta.
De curiozitate: care sint compilatoarele alea care aleg de capu' lor?

#5
Googlegps

Googlegps

    Member

  • Grup: Members
  • Posts: 242
  • Înscris: 01.11.2012

View PostIsaak, on 19 aprilie 2014 - 10:05, said:

Aici apare problema. Unele compilatoare accepta ob+100 dar 100+ob nu, unele (majoritatea) nu acceptă niciuna - eroare de ambiguitate, altele le acceptă pe ambele

E normal sa dea eroare intr-un astfel de caz. C++ -ul are niste reguli clare care trebuie respectate de orice compilator.Acele compilatoare care nu dau eroare au fost implementate gresit. Visual Studio e ok din punctul asta.
De curiozitate: care sint compilatoarele alea care aleg de capu' lor?

Am să mă interesez în legătură cu acele compilatoare... am să cercetez și eu (nu mai țin minte exact versiunile, dar m-a mirat deosebirea).
@potae .. Să știi că eu chiar nu am dormit 2 nopți gândindu-mă la această chestie (m-a tot frământat)!

Edited by Googlegps, 19 April 2014 - 14:24.


#6
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,236
  • Înscris: 24.02.2007
gcc vad ca apeleaza operator int() in ambele cazuri.

#7
Googlegps

Googlegps

    Member

  • Grup: Members
  • Posts: 242
  • Înscris: 01.11.2012
Încă o chestiune interesanta legată de exprimare.

Ideea pornește de la moșteniri. Aici apar 2 exprimări, care ca efect reprezintă același lucru.

Prima, cu care(mâncare), sunt de acord: O clasă moștenește toți membrii publici și protejați ai clasei de bază. Prin urmare, ea nu are acces la membrii privați (că na, de aia sunt privați) prin faptul că aceștia nu sunt nici măcar moșteniți.
A doua - nu sunt de acord cu ea - . O clasă moștenește toți membrii din clasa de bază (inclusiv cei privați), iar după aceea (după ce toți membrii sunt moșteniți) membrii privați ai clasei inițiale devin inutilizabili/ (sună al naibii de groaznic, dar da, am auzit-o și pe asta - nu de la un prof de facultă de data asta). Întrebare: ce rol ar mai avea atunci moștenirea membrilor privați....

Vreau aici să subliniez mai mult ideea din spatele mecanismului.
Unii consideră că o clasă moștenește toți membrii (toate tipurile de membrii), dar după aceea intervine ideea de private și prin urmare ce a fost private în clasa de bază este inutilizabil (dar există în fond) în clasa moștenitoare. Inutilizabil, dar ea există prin moștenire.

Eu consider prima variantă ca fiind corectă (defapt incompletă) având în vedere că nu moștenește constructorii, destructorii, operator =, prietenii. Reformulând ar veni: O clasă moștenește de la clasă de bază toți membrii publici și protejați cu excepția constructorilor, destructorilor, operatorului de atribuire și ai prietenilor. Practic el sare peste tot ce este private in clasa de bază.

De curiozitate: De ce fiecare crede ce vrea atunci când programează? Posted Image

Edited by Googlegps, 19 April 2014 - 21:26.


#8
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,236
  • Înscris: 24.02.2007
Normal ca vor exista in continuare si membrii privati deoarece clasa mostenitoare poate apela functii ale clasei de baza, ori aceasta are acces la/foloseste si membrii privati.

#9
Googlegps

Googlegps

    Member

  • Grup: Members
  • Posts: 242
  • Înscris: 01.11.2012
Am inteles. Deci ii mosteneste si pe membrii privati ai clasei de baza, doar ca mostenitorul nu are acces direct la ei.(doar prin metode ale clasei de baza)

#10
MrReason

MrReason

    Senior Member

  • Grup: Senior Members
  • Posts: 9,266
  • Înscris: 08.10.2010

View PostGooglegps, on 19 aprilie 2014 - 21:24, said:

Prima, cu care(mâncare), sunt de acord: O clasă moștenește toți membrii publici și protejați ai clasei de bază. Prin urmare, ea nu are acces la membrii privați (că na, de aia sunt privați) prin faptul că aceștia nu sunt nici măcar moșteniți.

Imagineaza-ti ca ai o clasa oarecare ce are printre altele o variabila privata name si o functie publica setName ce va atribui un nume varibilei private. Acum imagineaza-ti ca se deriva o alta clasa, care evident va mosteni functia setName. Daca variabila privata nu e mostenita deloc, unde crezi ca va fi stocat acel nume?

#11
Googlegps

Googlegps

    Member

  • Grup: Members
  • Posts: 242
  • Înscris: 01.11.2012
Am inteles. Practic, se mostenesc si membrii privati DAR acestia nu vor putea fi utilizati de metodele proprii clasei mostenitoare (putand fi accesate doar de metodele mostenite).

E interesanta ideea că se moștenește private-ul de la clasa de bază, dar membrii proprii clasei derivate NU o pot utiliza (doar metodele mostenite)

Edited by Googlegps, 20 April 2014 - 20:13.


#12
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,236
  • Înscris: 24.02.2007
Gandeste-te la o clasa precum la o structura.
Clasa de baza stocheaza parametrii x, y, z in primele pozitii din memorie.
Clasa derivata stocheaza parametrii x, y, z iar dupa ei mai stocheaza a, b, c.
Cum clasa derivata trebuie sa poata fi oricand cast-uita la clasa de baza, acest lucru se realizeaza foarte simplu, cine foloseste un pointer la clasa derivata dar nu stie decat ca e o clasa de baza, poate bine-mersi accesa parametrii x, y, z fiindca-s tot la inceputul zonei de memorie ocupata de clasa/structura.

private/public/protected sunt doar mecanisme ale compilatorului de a-ti da peste degete daca vrei sa faci ceva nepermis

#13
just0rz

just0rz

    Junior Member

  • Grup: Members
  • Posts: 146
  • Înscris: 14.01.2014
Faptul ca declari un membru ca fiind privat nu faci altceva decat de a-l ascunde si nicidecum de a impiedica mostenirea acestuia.

De fapt public, protected si private sunt rezultatul direct al incapsularii.

#14
magic-gabi

magic-gabi

    Senior Member

  • Grup: Senior Members
  • Posts: 2,925
  • Înscris: 04.07.2006

View PostGooglegps, on 20 aprilie 2014 - 20:10, said:

Am inteles. Practic, se mostenesc si membrii privati DAR acestia nu vor putea fi utilizati de metodele proprii clasei mostenitoare (putand fi accesate doar de metodele mostenite).
E interesanta ideea ca se mo?tene?te private-ul de la clasa de baza, dar membrii proprii clasei derivate NU o pot utiliza (doar metodele mostenite)
In C++ orice se poate :D. Daca vrei sa te convingi ca o instanta a unei subclase trage cu ea toti membrii superclasei in RAM am scris urmatorul program:
#include <iostream>
class A
{
private:
	int a;
public:
	A():a(0) {}
	void printA() { std::cout << "a privat din A este: " << a << "\n"; }
};
class B: public A
{
private:
	int b;
public:
	B():b(-1) {}
	/* o mare prostie, fac cast la inceputul obiectului in memorie si pentru ca il mosteneste pe A, inseamna ca
	exista un int in memoria obiectului si il scriu subscriu cu 3 deci int a exista in memoria oricarui obiect de tip B */
	void porcarie() { int* a = reinterpret_cast<int*>(this); *a=3;  }
	void printB() { std::cout << "b privat din B este: " << b << "\n"; }
};
int main()
{
	//daca sizeof(int) == 4 (32 biti) atunci:
	std::cout <<  sizeof(A) << "\n"; //4
	std::cout << sizeof(B) << "\n"; //8, deci avem si int a si int b
	B b;
	b.printA(); // 0
	b.printB(); // -1
	b.porcarie();
	b.printA(); // 3 !!! am modificat variabila privata a clasei A printr-un obiect de tip B
	b.printB(); // -1, asta a ramas la fel
	return 0;
};

https://ideone.com/6QASds arata ca returneaza cum am zis mai sus. Daca nu intelegi ceva, te rog sa imi spui.

View PostGooglegps, on 18 aprilie 2014 - 23:34, said:

- fie transforma 100 în obiect al clasei, ?i face sumare dintre 2 obiecte (prin operator+ definit).

Nu ar trebui sa transforme 100 in obiect al clasei decat daca clasa are un constructor care primeste
un int dar nu este declarat cu explicit. De aici cred ca e confuzia ta. Daca nu stii ce e ala atunci ar fi bine inainte sa te uiti aici: http://en.cppreferen...nguage/explicit

Cazul fara constructor explicit:
class A
{
	int m_A;
public:
	A( int i = -1 ):m_A(i) {}
	operator int() { return m_A; }
	A operator+(const A& a) {
		A rez;
		rez.m_A = a.m_A + m_A;
		return rez;
	}
};
int main()
{
	A a;
	A x = 1+a; // apeleaza operatorul int() si pe urma constructorul A
	A y = a+1; // nu are de ce sa mearga, eroare de ambiguitate
	/*   
	 * daca se comenteaza operatorul int(), se face 1 obiect al clasei A si se apeleaza A operator+ dar nu mai merge adunarea de sus
	 * daca se comenteaza operatorul A operator+, se face cast la int si se face adunare de 2 int-uri si merge si adunarea de sus
	*/
			   
	return 0;
}


iar cu explicit:
class A
{
	int m_A;
public:
	explicit A( int i = -1 ):m_A(i) {}
	operator int() { return m_A; }
	A operator+(const A& a) {
		A rez;
		rez.m_A = a.m_A + m_A;
		return rez;
	}
};
int main()
{
	A a;
	int x = 1+a; // apeleaza operatorul int() si face adunare intre 2 intregi
	int y = a+1; // apeleaza operatorul int() si face adunare intre 2 intregi
	return 0;
}

Daca nu de aici era problema, te rog sa imi spui :).

PS: Cum fac sa fie codul colorat :D?

Anunturi

Chirurgia cranio-cerebrală minim invazivă Chirurgia cranio-cerebrală minim invazivă

Tehnicile minim invazive impun utilizarea unei tehnologii ultramoderne.

Endoscoapele operatorii de diverse tipuri, microscopul operator dedicat, neuronavigația, neuroelectrofiziologia, tehnicile avansate de anestezie, chirurgia cu pacientul treaz reprezintă armamentarium fără de care neurochirurgia prin "gaura cheii" nu ar fi posibilă. Folosind tehnicile de mai sus, tratăm un spectru larg de patologii cranio-cerebrale.

www.neurohope.ro

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

Forumul Softpedia foloseste "cookies" pentru a imbunatati experienta utilizatorilor Accept
Pentru detalii si optiuni legate de cookies si datele personale, consultati Politica de utilizare cookies si Politica de confidentialitate