Sdílet prostřednictvím


Standardní převody

Jazyk C++ definuje převody mezi základními typy. Definuje také převody pro ukazatel, odkaz a pro odvozené typy ukazatele na člena. Tyto převody se nazývají standardní převody.

Tato část popisuje následující standardní převody:

  • Integrální povýšení

  • Integrální převody

  • Převody s plovoucí desetinnou čárkou

  • Převody s plovoucí desetinnou čárkou a integrální převody

  • Aritmetické převody

  • Převody ukazatele

  • Převody odkazů

  • Převody ukazatele na člena

    Poznámka:

    Uživatelské typy mohou zadat své vlastní převody. Převod uživatelem definovaných typů je pokryt konstruktory a převody.

Následující kód provede převody (v tomto příkladu integrální povýšení):

long  long_num1, long_num2;
int   int_num;

// int_num promoted to type long prior to assignment.
long_num1 = int_num;

// int_num promoted to type long prior to multiplication.
long_num2 = int_num * long_num2;

Výsledkem převodu je l-hodnota pouze v případě, že vytvoří typ odkazu. Například uživatelem definovaný převod deklarovaný jako operator int&() vrátí odkaz a je l-hodnota. Převod deklarovaný jako operator int() vrací objekt a není l-hodnota.

Integrální povýšení

Objekty celočíselného typu lze převést na jiný širší integrální typ, tj. typ, který může představovat větší sadu hodnot. Tento rozšiřující typ převodu se nazývá celočíselné povýšení. Při celočíselném povýšení můžete ve výrazu použít následující typy, kdykoli lze použít jiný celočíselný typ:

  • Objekty, literály a konstanty typu char a short int

  • Výčtové typy

  • int bitová pole

  • Enumerátory

Zvýšení úrovně jazyka C++ je "zachování hodnoty", protože hodnota po povýšení je zaručena, že bude stejná jako hodnota před povýšením. U povýšení zachování hodnot jsou objekty kratších integrálních typů (například bitových polí nebo objektů typu char) povýšeny na typ int , pokud int mohou představovat úplný rozsah původního typu. Pokud int nelze reprezentovat celý rozsah hodnot, objekt je povýšen na typ unsigned int. I když je tato strategie stejná jako ta, kterou používá standard C, neuchovávají převody pro zachování hodnot "ememočnost" objektu.

Povýšení typu zachovávající hodnotu a povýšení typu, která normálně zachovávají znaménko, vrátí stejné výsledky. Pokud se však upřednostněný objekt zobrazí jako:

  • Operand /, , %, /=<%=<=, , , nebo >>=

    Tyto operátory spoléhají pro stanovení výsledku na znaménko. Povýšení pro zachování hodnot a zachování znaménka vytváří při použití těchto operandů různé výsledky.

  • Levý operand >> nebo >>=

    Tyto operátory zachází se znaménkem a nepřiřazenými množstvími v operaci směny odlišně. U podepsaných množství se operace pravého posunu rozšíří znaménko do uvolněných bitových pozic, zatímco uvolněné bitové pozice jsou v množství bez znaménka vyplněné nulou.

  • Argument přetížené funkce nebo operand přetíženého operátoru, který závisí na podepsání typu operandu pro porovnávání argumentů. Další informace o definování přetížených operátorů naleznete v tématu Přetížené operátory.

Integrální převody

Integrální převody jsou převody mezi integrálními typy. Integrální typy jsou char, short (nebo short int), int, longa long long. Tyto typy mohou být kvalifikované s signed nebo unsigneda unsigned mohou být použity jako zkratka pro unsigned int.

Podepsáno k nepodepsané

Objekty celočíselných typů se znaménkem lze převést na odpovídající typy bez znaménka. Když dojde k těmto převodům, skutečný bit se nezmění. Interpretace dat se ale změní. Vezměte v úvahu tento kód:

#include <iostream>

using namespace std;
int main()
{
    short  i = -3;
    unsigned short u;

    cout << (u = i) << "\n";
}
// Output: 65533

V předchozím příkladu je definována signed shortia inicializována na záporné číslo. Výraz (u = i) způsobí i převod na před unsigned short přiřazením .u

Nepodepsané k podepsání

Objekty celočíselných typů bez znaménka lze převést na odpovídající typy se znaménkem. Pokud je však hodnota bez znaménka mimo reprezentovatelný rozsah typu znaménka, výsledek nebude mít správnou hodnotu, jak je znázorněno v následujícím příkladu:

#include <iostream>

using namespace std;
int main()
{
short  i;
unsigned short u = 65533;

cout << (i = u) << "\n";
}
//Output: -3

V předchozím příkladu je unsigned short integrální objekt, u který musí být převeden na podepsané množství k vyhodnocení výrazu (i = u). Protože jeho hodnota nemůže být správně reprezentována v objektu signed short, data jsou nesprávně interpretována, jak je znázorněno.

Převody s plovoucí desetinou čárkou

Objekt plovoucího typu lze bezpečně převést na přesnější typ s plovoucí desetinou čárkou – to znamená, že převod nezpůsobí ztrátu významnosti. Například převody z float do double nebo z double do long double jsou bezpečné a hodnota se nezmění.

Objekt typu s plovoucí desetinnou čárkou lze také převést na méně přesný typ, pokud je v rozsahu reprezentovatelném tímto typem. (Viz Plovoucí limity pro rozsahy plovoucích typů.) Pokud původní hodnota není přesně reprezentovatelná, můžete ji převést na další vyšší nebo další nižší reprezentovatelnou hodnotu. Pokud taková hodnota neexistuje, výsledek není definován. Představte si následující příklad:

cout << (float)1E300 << endl;

Maximální hodnota reprezentovatelná typem float je 3,402823466E38, což je mnohem menší číslo než 1E300. Proto je číslo převedeno na nekonečno a výsledek je "inf".

Převody mezi celočíselným a plovoucí desetinou čárkou

Určité výrazy mohou způsobit převod objektů typu s plovoucí desetinnou čárkou na celočíselné typy nebo naopak. Pokud je objekt celočíselného typu převeden na plovoucí typ a původní hodnota není přesně reprezentovatelná, výsledek je buď další vyšší, nebo další nižší reprezentovatelná hodnota.

Při převodu objektu typu s plovoucí desetinnou čárkou na celočíselný typ je zlomková část zkrácena nebo zaokrouhlena směrem k nule. Číslo jako 1,3 se převede na 1 a -1,3 se převede na -1. Pokud je zkrácená hodnota vyšší než nejvyšší reprezentovatelná hodnota nebo nižší než nejnižší reprezentovatelná hodnota, výsledek není definován.

Aritmetické převody

Mnoho binárních operátorů (probíraných ve výrazech s binárními operátory) způsobuje převody operandů a výsledky se vrátí stejným způsobem. Převody, které tyto operátory způsobují, se nazývají obvyklé aritmetické převody. Aritmetické převody operandů, které mají různé nativní typy, se provádějí, jak je znázorněno v následující tabulce. Typy typedef se chovají podle svých základních nativních typů.

Podmínky pro převod typu

Splněné podmínky Převod
Jeden operand je typu long double. Jiný operand je převeden na typ long double.
Předchozí podmínka není splněna a operand je typu double. Jiný operand je převeden na typ double.
Předchozí podmínky nejsou splněny a operand je typu float. Jiný operand je převeden na typ float.
Předcházející podmínky nebyly splněny (žádný z operandů není typ s plovoucí desetinnou čárkou). Operandy získávají celočíselné povýšení následujícím způsobem:

- Je-li jeden operand typu unsigned long, druhý operand je převeden na typ unsigned long.
- Pokud předchozí podmínka není splněna, a pokud je jeden operand typu long a druhý typ unsigned int, oba operandy jsou převedeny na typ unsigned long.
- Pokud předchozí dvě podmínky nejsou splněny, a pokud je jeden operand typu long, druhý operand je převeden na typ long.
- Pokud předchozí tři podmínky nejsou splněny, a pokud je jeden operand typu unsigned int, druhý operand je převeden na typ unsigned int.
- Pokud nejsou splněny žádné z předchozích podmínek, oba operandy jsou převedeny na typ int.

Následující kód znázorňuje pravidla převodu, která jsou popsána v tabulce:

double dVal;
float fVal;
int iVal;
unsigned long ulVal;

int main() {
   // iVal converted to unsigned long
   // result of multiplication converted to double
   dVal = iVal * ulVal;

   // ulVal converted to float
   // result of addition converted to double
   dVal = ulVal + fVal;
}

První příkaz v předchozím příkladu znázorňuje násobení dvou celočíselných typů, iVal a ulVal. Splněná podmínka je, že žádný operand není typu plovoucí a jeden operand je typu unsigned int. Takže druhý operand , iValje převeden na typ unsigned int. Výsledek se pak přiřadí .dVal Zde splněná podmínka je, že jeden operand je typu double, takže unsigned int výsledek násobení je převeden na typ double.

Druhý příkaz v předchozím příkladu ukazuje sčítání a float celočíselný typ: fVal a ulVal. Proměnná ulVal se převede na typ float (třetí podmínka v tabulce). Výsledek sčítání se převede na typ double (druhá podmínka v tabulce) a přiřadí se .dVal

Převody ukazatele

Ukazatele lze převádět během přiřazení, inicializace, porovnání a v jiných výrazech.

Ukazatel na třídy

Existují dva případy, kdy lze ukazatel na třídu převést na ukazatel na základní třídu.

Prvním případem je, když je zadaná základní třída přístupná a převod je jednoznačný. Další informace o nejednoznačných odkazech na základní třídu naleznete v tématu Více základních tříd.

Určuje, zda je základní třída přístupná, závisí na druhu dědičnosti použité při odvození. Představte si dědičnost znázorněnou na následujícím obrázku:

Diagram showing an inheritance graph and base class accessibility.

Diagram znázorňuje základní třídu A. Třída B dědí z A prostřednictvím privátní chráněné veřejné. Třída C dědí z B prostřednictvím veřejné B.

Graf dědičnosti znázorňující přístupnost základní třídy

Následující tabulka ukazuje přístupnost základní třídy pro situaci znázorněnou na obrázku.

Typ funkce Derivace Převod z

B* k A* právnímu?
Externí (ne funkce s oborem třídy) Soukromé No
Chráněno No
Veřejný Ano
Členová funkce B (v rozsahu B) Soukromé Ano
Chráněno Ano
Veřejný Ano
Členová funkce jazyka C (v oboru jazyka C) Soukromé No
Chráněno Ano
Veřejný Ano

Druhý případ, kdy lze ukazatel na třídu převést na ukazatel na základní třídu, je při použití explicitního převodu typu. Další informace o explicitních převodech typů naleznete v tématu Explicitní převod typu operátor.

Výsledkem takového převodu je ukazatel na podobjekt, část objektu, která je zcela popsána základní třídou.

Následující kód definuje dvě třídy a AB, kde B je odvozen z A. (Další informace o dědičnosti najdete v tématu Odvozené třídy.) Pak definuje bObjectobjekt typu Ba dva ukazatele (pA a pB) ukazující na objekt.

// C2039 expected
class A
{
public:
    int AComponent;
    int AMemberFunc();
};

class B : public A
{
public:
    int BComponent;
    int BMemberFunc();
};
int main()
{
   B bObject;
   A *pA = &bObject;
   B *pB = &bObject;

   pA->AMemberFunc();   // OK in class A
   pB->AMemberFunc();   // OK: inherited from class A
   pA->BMemberFunc();   // Error: not in class A
}

Ukazatel pA je typu A *, který lze interpretovat jako "ukazatel na objekt typu A." Členové bObject (například BComponent a BMemberFunc) jsou jedineční pro typ B a jsou proto nepřístupní prostřednictvím pA. Ukazatel pA umožňuje přístup pouze k těmto charakteristikám (členské funkce a data) objektu definovaného ve třídě A.

Ukazatel na funkci

Ukazatel na funkci lze převést na typ void *, pokud je typ void * dostatečně velký pro uložení ukazatele.

Ukazatel na void

Ukazatele na typ void lze převést na ukazatele na jakýkoli jiný typ, ale pouze s explicitním přetypováním (na rozdíl od jazyka C). Ukazatel na libovolný typ lze implicitně převést na ukazatel na typ void. Ukazatel na neúplný objekt typu lze převést na ukazatel void na (implicitně) a zpět (explicitně). Výsledek takového převodu je roven hodnotě původního ukazatele. Objekt je považován za neúplný, pokud je deklarován, ale není k dispozici dostatek informací k určení jeho velikosti nebo základní třídy.

Ukazatel na jakýkoli objekt, který není const nebo volatile lze implicitně převést na ukazatel typu void *.

const a volatile – ukazatele

C++ neposkytuje standardní převod z typu const nebo volatile typu na typ, který není const nebo volatilenení . Libovolné druhy převodu lze však určit pomocí přetypování explicitních typů (včetně převodů, které nejsou bezpečné).

Poznámka:

Ukazatele jazyka C++ na členy s výjimkou ukazatelů na statické členy se liší od běžných ukazatelů a nemají stejné standardní převody. Ukazatele na statické členy jsou normální ukazatele a mají stejné převody jako normální ukazatele.

Převody ukazatele null

Celočíselný konstantní výraz, který se vyhodnotí jako nula nebo takový výraz přetypovaný na typ ukazatele, se převede na ukazatel, který se nazývá ukazatel null. Tento ukazatel vždy porovnává nerovný ukazatel s ukazatelem na jakýkoli platný objekt nebo funkci. Výjimkou jsou ukazatele na založené objekty, které můžou mít stejný posun a stále odkazují na různé objekty.

V jazyce C++11 by měl být typ nullptr upřednostňovaný pro ukazatel null ve stylu jazyka C.

Převody výrazů ukazatele

Každý výraz typu pole lze převést na ukazatel stejného typu. Výsledkem převodu je ukazatel na první prvek pole. Následující příklad ukazuje takový převod:

char szPath[_MAX_PATH]; // Array of type char.
char *pszPath = szPath; // Equals &szPath[0].

Výraz, jehož výsledkem je funkce vracející určitý typ, je převeden na ukazatel na funkci vracející tento typ kromě těchto případů:

  • Výraz se používá jako operand operátoru adresy (&).

  • Výraz je použit jako operand operátoru volání funkce.

Převody odkazů

Odkaz na třídu lze v těchto případech převést na odkaz na základní třídu:

  • Zadaná základní třída je přístupná.

  • Převod je jednoznačný. (Další informace o nejednoznačných odkazech na základní třídu najdete v tématu Více základních tříd.)

Výsledkem převodu je ukazatel na podobjekt, který představuje základní třídu.

Ukazatel na člen

Ukazatele na členy třídy lze převádět během přiřazení, inicializace, porovnání a v jiných výrazech. Tato část popisuje následující převody ukazatele na člen:

Ukazatel na člen základní třídy

Ukazatel na člen základní třídy lze převést na ukazatel na člen třídy z ní odvozené, pokud jsou splněny následující podmínky:

  • Inverzní převod z ukazatele na odvozenou třídu na ukazatel na základní třídu je přístupný.

  • Odvozená třída nedědí prakticky ze základní třídy.

Je-li levý operand ukazatel na člen, pravý operand musí být typu ukazatele na člen nebo konstantní výraz, který je vyhodnocen na hodnotu 0. Toto přiřazení je platné pouze v následujících případech:

  • Pravý operand je ukazatel na člen stejné třídy jako levý operand.

  • Levý operand je ukazatel na člen třídy odvozené veřejně a jednoznačně z třídy pravého operandu.

ukazatel null na převody členů

Celočíselný konstantní výraz, který se vyhodnotí jako nula, se převede na ukazatel null. Tento ukazatel vždy porovnává nerovný ukazatel s ukazatelem na jakýkoli platný objekt nebo funkci. Výjimkou jsou ukazatele na založené objekty, které můžou mít stejný posun a stále odkazují na různé objekty.

Následující kód znázorňuje definici ukazatele na člen i třídy A. Ukazatel pai je inicializován na hodnotu 0, což je nulový ukazatel.

class A
{
public:
int i;
};

int A::*pai = 0;

int main()
{
}

Viz také

Referenční dokumentace jazyka C++