Přetěžévání operátorů – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Přetěžévání operátorů – C / C++ – Fórum – Programujte.comPřetěžévání operátorů – C / C++ – Fórum – Programujte.com

 

Kubas
~ Anonymní uživatel
11 příspěvků
11. 11. 2019   #1
-
0
-

Ahoj, hraji si s funkcemi, které slouží k přetěžování operátorů a narazil jsem na jednu věc, kterou nechápu :(

mám třídu Cislo

//soubor Cislo.h, deklarovani hlavicek funkci
class Cislo
{
public:
	Cislo();
	~Cislo();
	//Cislo(Cislo& odkaz);///kontruktor pro kopirovani
	Cislo (int);
	const int ZiskejHodnotu() const { return hodnota; }
	 Cislo operator+(Cislo &odkaz);
	 operator int();
private:
	int hodnota;
};
//soubor Cislo.cpp
#include "Cislo.h"


Cislo::Cislo()
{
}

const Cislo Cislo::operator++(int param)
{
	//Cislo pom = *this;
	Cislo pom(*this);//volam konstruktor pro kopirovani
	hodnota++;
	return pom;
}

 Cislo Cislo::operator+(Cislo & odkaz)
{
	 int soucet = (int)(hodnota + odkaz.hodnota);
	 Cislo suma = soucet;
	return suma;
}

 Cislo::operator int()
 {
	 return hodnota;
 }

Cislo::~Cislo()
{
}

//Cislo::Cislo(Cislo & odkaz)
//{
//	 this->hodnota=odkaz.hodnota ;
//}
#include <iostream>
#include "Cislo.h"
int main()
{
	using namespace std;
	Cislo cislo=30, cislo2=60;
	cout << "prirazeni cislo=30\n";
	//Cislo soucet = cislo + cislo2;
	Cislo soucet(cislo.operator+(cislo2));
	cout << "soucet cisel je:\n"<<soucet.ZiskejHodnotu()<<endl;
}

Program pro součet dvou instancí objektu Cislo funguje, ale nepochopil jsem, že když si napíšu svůj vlastní kopírovací konstruktor, tak program vyžaduje po mě, abych tam přidal ještě funkci operator int();, která slouží k převodu (konverzi) instance objektu na celočíselnou proměnnou, bez ní to s navrženým kopírovacím kosntruktorem nejde a nevím proč jí to potřebuje, proč to tam do ní následně po provedení toho příkazu přiřazení do ní program skáče :(. Že když ten konstruktor pro kopírování vykomentuju a nechám tam ten výchozí, který si program sám vytváří, tak tuto funkci konverze z objektu na integer nepotřebuje (což chápu proč jí nepotřebuje). Prostě nechápu, kde je ten převod z instance objektu na celočíselnou proměnnou.

Doufám, že se mi to podařilo dobře vysvětlit co na tom nechápu :D

Díky moc za rady :) 

Nahlásit jako SPAM
IP: 62.141.28.–
Kubas
~ Anonymní uživatel
11 příspěvků
11. 11. 2019   #2
-
0
-

#1 Kubas
pardon všiml jsem si v tom souboru Cislo.cpp, že jsem tam omylem vymazal nesprávnou funkci, tahle je snad už správně :-)

#include "Cislo.h"


Cislo::Cislo()
{
}
Cislo::Cislo(int param):hodnota(param)
{

}

 Cislo Cislo::operator+(Cislo & odkaz)
{
	 int soucet = (int)(hodnota + odkaz.hodnota);
	 Cislo suma = soucet;
	return suma;
}

 Cislo::operator int()
 {
	 return hodnota;
 }

Cislo::~Cislo()
{
}

//Cislo::Cislo(Cislo & odkaz)
//{
//	 this->hodnota=odkaz.hodnota ;
//}
Nahlásit jako SPAM
IP: 62.141.28.–
gna
~ Anonymní uživatel
1851 příspěvků
11. 11. 2019   #3
-
0
-

Mně se to nepodařilo navodit (starý gcc/clang), ale tipuju, že to po tobě chce operator int, protože jako jediný použitelný konstruktor vidí ten pro int.

U toho kopírovacícho kontruktoru deklaruj tu referenci jako const.

Nahlásit jako SPAM
IP: 213.211.51.–
Staon0
Návštěvník
13. 12. 2020   #4
-
0
-

Otázka je už trochu starší, ale stejně zkusím odpovědět, protože se domnívám, že toto je nádherná ukázka toho, co se stane, pokud programátor v C++ nedodržuje const correctness.

Automaticky vygenerovaný kopírovací konstruktor nemá signaturu, tak jak jste ji napsal, ale následující: 

Cislo(const Cislo& odkaz);

Je zde na první pohled jen nepatrný rozdíl - const u reference na zdrojový objekt. Rozdíl ve skutečnosti je ale velmi podstatný: const umožňuje jako předaný argument zadat dočasnou proměnnou. Pokud const v deklaraci není, předaná hodnota musí být existující proměnná s životností přesahující výraz.

Vy ve svém programu používáte inicializaci přiřazením: 

Cislo cislo = 30;

Tento způsob inicializace vyžaduje použití kopírovacího konstruktoru. Tzn. překladač nejprve vytvoří dočasnou proměnnou typu Cislo inicializovanou konstruktorem s parametrem typu int, a pak vyvolá kopírovací konstruktor, kterému dočasnou proměnnou předá. Váš kopírovací konstruktor ovšem není schopný přijmout dočasnou proměnnou. Na aktuálních překladačích toto skončí s chybou překladu.

Na starších překladačích to může být složitější. Překladač totiž má oprávnění (standardem) tuto zbytečnou kopii odstranit a zinicializovat proměnnou přímo konstruktorem s parametrem int. Sice podle standardu musí zkontrolovat podmínky, jakoby optimalizaci nedělal, ale ne všichni to skutečně tak dělali (Watcom 10.6 to určitě nedělal). Pak se tato inicializace dokáže zkompilovat bez chyby, i když tam reálně chyba je.

Mimochodem, právě z tohoto důvodu je inicializace přiřazením ta nejhorší možná, kterou v C++ můžete použít. Lepší je inicializovat kulatými nebo složenými (od C++11) závorkami: 

Cislo a(10);
Cislo b{20};

Ani jedno není ideální, ale pořád jsou to lepší varianty než přiřazením. Doporučuji se tento zlozvyk odnaučit.

Bohužel nepíšete, na jakém překladači, se vám problém děl. A ani nepíšete přesnou chybu, co vám hlásí, ani na které řádce. Předpokládám, že šlo o řádku 

Cislo soucet = cislo + cislo2;

Podle standardu není žádný důvod zde chtít konverzi z Cislo na int. Ale protože se zdá, že váš překladač standard úplně nedodržuje, budu hádat, že došlo k následujícímu:

  • vyvolal se operátor +, sečetl obě čísla a vytvořila se dočasná proměnná typu Cislo s výsledkem.
  • Kompilátor zjistil, že nemůže použít váš kopírovací konstruktor, protože do něj nemůže poslat dočasnou proměnnou. Zde by normální překladač končil s chybou.
  • Váš překladač si ale všiml, že existuje konstruktor s typem int, že existuje automatická konverze z Cislo na int a že při optimalizaci odstranění volání kopírovacího konstruktoru může tyhle dvě věci spojit dohromady. Zavolal tedy konverzi na int, a jejím výsledkem zinicializoval proměnnou soucet.

Nahlásit jako SPAM
IP: 94.113.221.–
KIIV
~ Moderátor
+43
God of flame
20. 12. 2020   #5
-
+1
-
Zajímavé

#4 Staon
Jeste stoji za to zminit klicove slovo explicit, neni totiz nic horsiho, nez kdyz se zacnou implicitne prevadet ruzne hodnoty na objekty a pak pomoci pretizeneho operatoru int() zase zpet :D

Neco jako:

explicit Cislo (int);
explicit operator int() const;

Pred c++11 se taky musely delat silene hacky misto operator bool(), aby se z tech objektu ve vyrazech nahle nestaly booleany diky implicitnim konverzim.To ale vyresilo klicove slovo explicit. Bez toho ale vznikaly idiomy jako  https://www.artima.com/…afebool.html

Nahlásit jako SPAM
IP: 37.48.8.–
Program vždy dělá to co naprogramujete, ne to co chcete...
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 20 hostů

Podobná vlákna

Přetížení operátoru ^ — založil TauWich

Nastavení operátoru != — založil TomBar

Přetypování operátorů — založil Wimby

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý