CannibalSmith ([info]cannibalsmith) rakstīja [info]koderi kopienā,
@ 2007-11-24 20:00:00

Previous Entry  Add to memories!  Tell a Friend!  Next Entry
īpašību simulācija iekš C++
Ķipa getSomething() funkcijas bieži izmanto read-only klases mainīgo nolasīšanai. Bet es tak varu darīt šādi:
class Boo
{
public:
	Boo() : read_only_property(private_variable) { }
	const int& read_only_property;
private:
	int private_variable;
};
Bet ar šādu sintaksi es iegūstu pilnu property (kā, piemēram, C#) simulāciju. No ārpuses izskatīsies kā mainīgais, bet es iekšpusē varu ielikt izsaukuma apstrādi. Vienīgi ārpusē neuzrādīsies vērtības patiesais tips. Es gan varētu nosaukt viņu, piemēram, Tilpums_int...
class Pudele
{
public:
	Tilpums tilpums;
	class Tilpums
	{
	public:
		int operator =(int value) { tilpums = value; }
		operator int() { return tilpums; }
	private:
		int tilpums;
	};
};
Komentāri? Cik jēdzīgas vai nejēdzīgas ir šīs tehnikas? Vai tām ir pielietojums? Vai ir vēl kāds iemesls tās nelietot bez tā, ka tās ir pilnīgi ārpus vispār pieņemtā kodēšanas stila?

Edit: izlaboju kļūdas.


(Ierakstīt jaunu komentāru)


[info]bubu
2007-11-24 22:21 (saite)
Ar pirmo būs problēmas, ja gribēsi likt klasi std::vector konteinerā. Būs arī problēma ar objekta piešķiršanu pēc vērtības. Tb reāli tu esi aizliedzis operator = šai klasei.
Ja jau tev vajadzīgi tik daudz tie getteri, ka slinkums rakstīt getXXX() metodes, tad laiks padomāt par klases un tās izmantošanas pareizību. Es mēģinātu to funkcionalitāti, kas izmantot to tavu private_variable ienest kādas klases metodē. Jo tamdēļ jau metodes klasei izdomātas - lai kautko darītu, nevis tikai kalpotu par plikiem getteriem/setteriem - pēdējam ir izdomāts struct.
Pie tam tev līka sintakse ;) Boo() : ro_var(var) {}

Par otru - operator = nav labi atgriezt void. Vajadzētu atgriezt referenci uz *this.
Un vai šādi tev nesanāks rakstīt vairāk koda nekā uzrakstīt to pašu veco labo getteri un setteri - void setTilpums(int x) un int getTilpums() const. Gan mazāk jāraksta, gan visiem skaidrs, kas ar to domāts un nav jāpēta dīvainas klases, un ko ar tām ir jāiesāk.
Vēl arī - ja nu pēkšņi mainīsies prasības un uzstādot tilpumu nāksies padod divas vērtības (pudeles tilpums un pudeles izmērs) - tad operator = nevarēs saņemt divas vērtības tik vienkārši, ja vien neizmantos vēl kādu citu papildus klasi, taču setTilpums metodes gadījumā nāksies vienkārši pielikt vēl vienu argumentu.
Nu bet tas viss pēc vajadzības. Ja nu ir izdomāts, ka tā vajag, tad vajag. Tik mainīgā tipu gan neliec tā nosaukumā. Visi taču zin, cik Hungarian notation C++'ā ir īvils :)

(Atbildēt uz šo) (Diskusija)


[info]cannibalsmith
2007-11-24 22:44 (saite)
Es šeit necenšos atrisināt kādu konkrētu problēmu - man vienkārši ienāca prātā ideja.

Kā tas ir, esmu aizliedzis operator = ? Viņš tak tiek klāt private_variable.

Es nevaru atgriezt *this, jo pēc idejas tur nav ko atgriezt - tas objekts tak maskējas par propertiju! Es gan varētu atgriezt piešķirto vērtību - šajā gadījumā int.

Ja pēkšņi mainīsies prasības, un man būs get/set, tad es noteikti nelikšu klāt otru argumentu set funkcijai, jo tas ir pretrunā get/set funkciju idejai. Vēl pie tam, kā tad get funkcija atgrieztu divas vērtības? Pareizi būtu pielikt jaunu get/set funkciju kopu jeb šajā gadījumā - vēl vienu par propertiju maskējošos iekļauto klasi.

(Atbildēt uz šo) (Iepriekšējais) (Diskusija)


[info]bubu
2007-11-24 23:01 (saite)
Neprecīzi pateicu - gribēju teikt, ka esi aizliedzis defaulto konstruktoru, jo tas nezin kā var pārkopēt const referenci (tai neko piešķirt ta nevar!). Protams, ja pats implementē visām klasēm to operator = tad viss rullēs.
Ah jā - pareiz tu saki par to Tilpums::operator = atgriežamo vērtību. int ir jāatgriež.
Kā atgriezt divas vērtības? Vienkārši:
typedef std::pair<int, float> MyTwoValues;

MyTwoValues func()
{
    return std::make_pair(1, 15.0f);
}
boost::tuple ļauj atgriez līdz pat 10 vērtības :) Un vienmēr var arī padot funkcijas argumentos ne-const references uz vērtībām, kurās jāatgriež kautkas:
bool getNextThing(Thing& thing);
...
Thing thing;
while (getNextThing(thing))
{
    thing->doSomething();
}
Kāpēc lai divi argumenti būtu pretrunā ar set funkciju?
class Window
{
   void setPosition(int x, int y);
};

Es jau biju domājis tieši šādu gadījumu - kad datus veido vairāki aprakstāmie lielumi, nevis viens vienīgs. Slikts piemērs par to pudeles izmēru bij..

(Atbildēt uz šo) (Iepriekšējais) (Diskusija)


[info]cannibalsmith
2007-11-28 18:46 (saite)
Tas ir labs stils, tā darīt ar pair un tuple? It īpaši, kad mainīgie nav loģiski saistīti.

Ja atgriežamās vērtības ir argumenti (neconst references), tad tādu konstrukciju nevar likt lielākās izteiksmēs un ir obligāti jādeklarē mainīgais, kur glabāt rezultātu. Tas tak ir slikts stils, ne?
Ērti: doStuff(getValue());
Neērti: { int val; getValue(val); doStuff(val); }

(Atbildēt uz šo) (Iepriekšējais) (Diskusija)


[info]bubu
2007-11-28 20:18 (saite)
Labs stils noteikti neskaitās rakstīt sarežģītus funkciju izsaukumus:
doStuff(getValue(value1), getOtherValue(value2));

(Atbildēt uz šo) (Iepriekšējais)


Neesi iežurnalējies. Iežurnalēties?