Ricerca…
introduzione
Le parole chiave hanno un significato definito dallo standard C ++ e non possono essere utilizzate come identificatori. È illegale ridefinire le parole chiave utilizzando il preprocessore in qualsiasi unità di traduzione che include un'intestazione di libreria standard. Tuttavia, le parole chiave perdono il loro significato speciale all'interno degli attributi.
Sintassi
- asm ( string letterale );
- noexcept ( espressione ) // significato 1
- noxcept ( espressione costante ) // significato 2
- noexcept // significato 2
- dimensione dell'espressione unaria
- sizeof ( type-id )
- sizeof ... ( identificatore ) // dal C ++ 11
- typename nested-name- identificatore identificatore // significato 1
- typename template nested-name-specifier ( opt ) simple-template-id // che significa 1
- identificatore typename ( opt ) // significato 2
- typename ... identificatore ( opt ) // significato 2; dal C ++ 11
- typename identifier ( opt ) = type-id // che significa 2
- template < template-parameter-list > typename ... ( opt ) identifier ( opt ) // significato 3
- template < template-parameter-list > typename identifier ( opt ) = id-expression // significato 3
Osservazioni
L'elenco completo delle parole chiave è il seguente:
-
alignas
(dal C ++ 11) -
alignof
(dal C ++ 11) -
asm
-
auto
: dal C ++ 11 , prima del C ++ 11 -
bool
-
break
-
case
-
catch
-
char
-
char16_t
(dal C ++ 11) -
char32_t
(dal C ++ 11) -
class
-
const
-
constexpr
(dal C ++ 11) -
const_cast
-
continue
-
decltype
(dal C ++ 11) -
default
-
delete
per gestione memoria , per funzioni (dal C ++ 11) -
do
-
double
-
dynamic_cast
-
else
-
enum
-
explicit
-
export
-
extern
comeextern
di dichiarazione , nella specifica del collegamento , per i modelli -
false
-
float
-
for
-
friend
-
goto
-
if
-
inline
per funzioni , per namespace (dal C ++ 11), per variabili (dal C ++ 17) -
int
-
long
-
mutable
-
namespace
-
new
-
noexcept
(dal C ++ 11) -
nullptr
(dal C ++ 11) -
operator
-
private
-
protected
-
public
-
register
-
reinterpret_cast
-
return
-
short
-
signed
-
sizeof
-
static
-
static_assert
(dal C ++ 11) -
static_cast
-
struct
-
switch
-
template
-
this
-
thread_local
(dal C ++ 11) -
throw
-
true
-
try
-
typedef
-
typeid
-
typename
-
union
-
unsigned
-
using
per redeclare un nome , per alias uno spazio dei nomi , per alias un tipo -
virtual
per funzioni , per classi base -
void
-
volatile
-
wchar_t
-
while
I token final
e override
non sono parole chiave. Possono essere usati come identificatori e hanno un significato speciale solo in determinati contesti.
I token and
, and_eq
, bitand
, bitor
, compl
, not
, not_eq
, or
, or_eq
, xor
e xor_eq
sono ortografie alternative di &&
, &=
, &
, |
, ~
!
, !=
, ||
, |=
, ^
, e ^=
, rispettivamente. Lo standard non li tratta come parole chiave, ma sono parole chiave a tutti gli effetti, dal momento che è impossibile ridefinirli o usarli per indicare qualcosa di diverso dagli operatori che rappresentano.
I seguenti argomenti contengono spiegazioni dettagliate di molte delle parole chiave in C ++, che servono a scopi fondamentali come la denominazione di tipi di base o il controllo del flusso di esecuzione.
asm
La parola chiave asm
accetta un singolo operando, che deve essere una stringa letterale. Ha un significato definito dall'implementazione, ma in genere viene passato all'assemblatore dell'implementazione, con l'output dell'assembler incorporato nell'unità di traduzione.
L'istruzione asm
è una definizione , non un'espressione , quindi può apparire sia nell'ambito del blocco che dello spazio dei nomi (incluso l'ambito globale). Tuttavia, poiché l'assembly inline non può essere vincolato dalle regole del linguaggio C ++, asm
potrebbe non apparire all'interno di una funzione constexpr
.
Esempio:
[[noreturn]] void halt_system() {
asm("hlt");
}
esplicito
Quando viene applicato a un costruttore di argomento singolo, impedisce che venga utilizzato il costruttore per eseguire conversioni implicite.
class MyVector { public: explicit MyVector(uint64_t size); }; MyVector v1(100); // ok uint64_t len1 = 100; MyVector v2{len1}; // ok, len1 is uint64_t int len2 = 100; MyVector v3{len2}; // ill-formed, implicit conversion from int to uint64_t
Dal momento che C ++ 11 ha introdotto gli elenchi di inizializzatori, in C ++ 11 e versioni successive, l'
explicit
può essere applicato a un costruttore con un numero qualsiasi di argomenti, con lo stesso significato del caso a argomento singolo.struct S { explicit S(int x, int y); }; S f() { return {12, 34}; // ill-formed return S{12, 34}; // ok }
Se applicato a una funzione di conversione, impedisce che la funzione di conversione venga utilizzata per eseguire conversioni implicite.
class C { const int x; public: C(int x) : x(x) {} explicit operator int() { return x; } }; C c(42); int x = c; // ill-formed int y = static_cast<int>(c); // ok; explicit conversion
noexcept
Un operatore unario che determina se la valutazione del proprio operando può propagare un'eccezione. Si noti che i corpi delle funzioni chiamate non vengono esaminati, quindi
noexcept
può produrre falsi negativi. L'operando non viene valutato.#include <iostream> #include <stdexcept> void foo() { throw std::runtime_error("oops"); } void bar() {} struct S {}; int main() { std::cout << noexcept(foo()) << '\n'; // prints 0 std::cout << noexcept(bar()) << '\n'; // prints 0 std::cout << noexcept(1 + 1) << '\n'; // prints 1 std::cout << noexcept(S()) << '\n'; // prints 1 }
In questo esempio, anche se
bar()
non può mai generare un'eccezione,noexcept(bar())
è ancora falso perché il fatto chebar()
non possa propagare un'eccezione non è stato esplicitamente specificato.Quando si dichiara una funzione, specifica se la funzione può propagare o meno un'eccezione. Da solo, dichiara che la funzione non può propagare un'eccezione. Con un argomento tra parentesi, dichiara che la funzione può o non può propagare un'eccezione a seconda del valore di verità dell'argomento.
void f1() { throw std::runtime_error("oops"); } void f2() noexcept(false) { throw std::runtime_error("oops"); } void f3() {} void f4() noexcept {} void f5() noexcept(true) {} void f6() noexcept { try { f1(); } catch (const std::runtime_error&) {} }
In questo esempio, abbiamo dichiarato che
f4
,f5
ef6
non possono propagare eccezioni. (Anche se un'eccezione può essere generata durante l'esecuzione dif6
, viene catturata e non è consentita la propagazione fuori dalla funzione.) Abbiamo dichiarato chef2
può propagare un'eccezione. Quando l'noexcept
è omesso, è equivalente anoexcept(false)
, quindi abbiamo implicitamente dichiarato chef1
ef3
possono propagare eccezioni, anche se non possono essere generate eccezioni durante l'esecuzione dif3
.
Indipendentemente dal fatto che una funzione non noexcept
fa parte del tipo di funzione: cioè nell'esempio precedente, f1
, f2
e f3
hanno tipi diversi da f4
, f5
e f6
. Pertanto, noexcept
è anche significativo nei puntatori di funzione, negli argomenti del modello e così via.
void g1() {}
void g2() noexcept {}
void (*p1)() noexcept = &g1; // ill-formed, since g1 is not noexcept
void (*p2)() noexcept = &g2; // ok; types match
void (*p3)() = &g1; // ok; types match
void (*p4)() = &g2; // ok; implicit conversion
typename
Quando seguito da un nome qualificato,
typename
specifica che si tratta del nome di un tipo. Questo è spesso richiesto nei template, in particolare, quando lo specificatore del nome annidato è un tipo dipendente diverso dall'istanza corrente. In questo esempio,std::decay<T>
dipende dal parametro di modelloT
, quindi per denominare il tipo ditype
nidificato, è necessario prefissare l'intero nome qualificato contypename
. Per ulteriori informazioni, vedere Dove e perché devo inserire le parole chiave "template" e "typename"?template <class T> auto decay_copy(T&& r) -> typename std::decay<T>::type;
Introduce un parametro di tipo nella dichiarazione di un modello . In questo contesto, è intercambiabile con la
class
.template <typename T> const T& min(const T& x, const T& y) { return b < a ? b : a; }
typename
può anche essere usato quando si dichiara un parametro template template , che precede il nome del parametro, proprio come laclass
.template <template <class T> typename U> void f() { U<int>::do_it(); U<double>::do_it(); }
taglia di
Un operatore unario che produce la dimensione in byte del suo operando, che può essere un'espressione o un tipo. Se l'operando è un'espressione, non viene valutato. La dimensione è un'espressione costante di tipo std::size_t
.
Se l'operando è un tipo, deve essere tra parentesi.
- È illegale applicare
sizeof
a un tipo di funzione. - È illegale applicare
sizeof
a un tipo incompleto, inclusovoid
. - Se sizeof è applicato a un tipo di riferimento
T&
oaT&&
, è equivalente asizeof(T)
. - Quando
sizeof
viene applicato a un tipo di classe, restituisce il numero di byte in un oggetto completo di quel tipo, inclusi eventuali byte di riempimento nel mezzo o alla fine. Pertanto, un'espressionesizeof
non può mai avere un valore pari a 0. Vedere il layout dei tipi di oggetto per ulteriori dettagli. - I
char
,signed char
eunsigned char
hanno una dimensione pari a 1. Al contrario, un byte è definito come la quantità di memoria richiesta per memorizzare un oggettochar
. Non significa necessariamente 8 bit, poiché alcuni sistemi hanno oggettichar
più lunghi di 8 bit.
Se expr è un'espressione, sizeof(
expr )
è equivalente a sizeof(T)
dove T
è il tipo di expr.
int a[100];
std::cout << "The number of bytes in `a` is: " << sizeof a;
memset(a, 0, sizeof a); // zeroes out the array
L'operatore sizeof...
produce il numero di elementi in un pacchetto di parametri.
template <class... T>
void f(T&&...) {
std::cout << "f was called with " << sizeof...(T) << " arguments\n";
}
Parole chiave diverse
vuoto C ++
Se utilizzato come tipo restituito dalla funzione, la parola chiave void specifica che la funzione non restituisce un valore. Se utilizzato per la lista dei parametri di una funzione, void specifica che la funzione non ha parametri. Se utilizzato nella dichiarazione di un puntatore, void specifica che il puntatore è "universale".
Se il tipo di puntatore è void *, il puntatore può puntare a qualsiasi variabile che non è dichiarata con la parola chiave const o volatile. Un puntatore void non può essere dereferenziato a meno che non venga lanciato su un altro tipo. Un puntatore vuoto può essere convertito in qualsiasi altro tipo di puntatore dati.
Un puntatore vuoto può puntare a una funzione, ma non a un membro della classe in C ++.
void vobject; // C2182 void *pv; // okay int *pint; int i; int main() { pv = &i; // Cast optional in C required in C++ pint = (int *)pv;
C ++ volatile
Un qualificatore di tipo che è possibile utilizzare per dichiarare che un oggetto può essere modificato nel programma dall'hardware.
volatile declarator ;
C ++ virtuale
La parola chiave virtuale dichiara una funzione virtuale o una classe base virtuale.
virtual [type-specifiers] member-function-declarator virtual [access-specifier] base-class-name
parametri
specificatori di testo Specifica il tipo di ritorno della funzione membro virtuale.
membro-funzione-dichiaratore Dichiara una funzione membro.
access-specificatore Definisce il livello di accesso alla classe base, pubblica, protetta o privata. Può apparire prima o dopo la parola chiave virtuale.
nome-classe-base Identifica un tipo di classe precedentemente dichiarato
questo puntatore
Questo puntatore è un puntatore accessibile solo all'interno delle funzioni membro non statiche di una classe, di una struct o di un tipo di unione. Punta all'oggetto per cui viene chiamata la funzione membro. Le funzioni membro statiche non hanno questo puntatore.
this->member-identifier
Un puntatore di questo oggetto non fa parte dell'oggetto stesso; non si riflette nel risultato di una dichiarazione sizeof sull'oggetto. Invece, quando una funzione membro non statico viene chiamata per un oggetto, l'indirizzo dell'oggetto viene passato dal compilatore come argomento nascosto alla funzione. Ad esempio, la seguente chiamata di funzione:
myDate.setMonth( 3 );
can be interpreted this way:
setMonth( &myDate, 3 );
The object's address is available from within the member function as the this pointer. Most uses of this are implicit. It is legal, though unnecessary, to explicitly use this when referring to members of the class. For example:
void Date::setMonth( int mn )
{
month = mn; // These three statements
this->month = mn; // are equivalent
(*this).month = mn;
}
The expression *this is commonly used to return the current object from a member function:
return *this;
The this pointer is also used to guard against self-reference:
if (&Object != this) {
// do not execute in cases of self-reference
provare, lanciare e prendere istruzioni (C ++)
- Per implementare la gestione delle eccezioni in C ++, usate try, throw e catch espressioni.
- Innanzitutto, utilizzare un blocco try per racchiudere una o più istruzioni che potrebbero generare un'eccezione.
- Un'espressione di lancio indica che una condizione eccezionale, spesso un errore, si è verificata in un blocco try. È possibile utilizzare un oggetto di qualsiasi tipo come l'operando di un'espressione di lancio. In genere, questo oggetto viene utilizzato per comunicare informazioni sull'errore. Nella maggior parte dei casi, si consiglia di utilizzare la classe std :: exception o una delle classi derivate definite nella libreria standard. Se uno di questi non è appropriato, si consiglia di derivare la propria classe di eccezione da std :: exception.
- Per gestire le eccezioni che possono essere lanciate, implementare uno o più blocchi catch immediatamente dopo un blocco try. Ogni blocco di cattura specifica il tipo di eccezione che può gestire.
MyData md;
try {
// Code that could throw an exception
md = GetNetworkResource();
}
catch (const networkIOException& e) {
// Code that executes when an exception of type
// networkIOException is thrown in the try block
// ...
// Log error message in the exception object
cerr << e.what();
}
catch (const myDataFormatException& e) {
// Code that handles another exception type
// ...
cerr << e.what();
}
// The following syntax shows a throw expression
MyData GetNetworkResource()
{
// ...
if (IOSuccess == false)
throw networkIOException("Unable to connect");
// ...
if (readError)
throw myDataFormatException("Format error");
// ...
}
Il codice dopo la clausola try è la sezione di codice protetta. L'espressione di tiro lancia - cioè, solleva - un'eccezione. Il blocco di codice dopo la clausola catch è il gestore di eccezioni. Questo è il gestore che cattura l'eccezione generata se i tipi nelle espressioni throw e catch sono compatibili.
try {
throw CSomeOtherException();
}
catch(...) {
// Catch all exceptions – dangerous!!!
// Respond (perhaps only partially) to the exception, then
// re-throw to pass the exception to some other handler
// ...
throw;
}
amico (C ++)
In alcune circostanze, è più conveniente concedere l'accesso a livello di membro a funzioni che non sono membri di una classe o di tutti i membri in una classe separata. Solo l'implementatore della classe può dichiarare chi sono i suoi amici. Una funzione o una classe non possono dichiararsi amici di qualsiasi classe. In una definizione di classe, utilizzare la parola chiave friend e il nome di una funzione non membro o un'altra classe per concederne l'accesso ai membri privati e protetti della classe. In una definizione di modello, un parametro di tipo può essere dichiarato come amico.
Se dichiari una funzione amico che non è stata dichiarata in precedenza, tale funzione viene esportata nell'ambito di protezione non classificatore.
class friend F friend F; class ForwardDeclared;// Class name is known. class HasFriends { friend int ForwardDeclared::IsAFriend();// C2039 error expected };
funzioni amico
Una funzione amico è una funzione che non è un membro di una classe ma ha accesso ai membri privati e protetti della classe. Le funzioni amico non sono considerate membri della classe; sono normali funzioni esterne a cui sono assegnati privilegi speciali di accesso.
Gli amici non fanno parte dell'ambito della classe e non vengono chiamati utilizzando gli operatori di selezione membri (. E ->) a meno che non siano membri di un'altra classe.
Una funzione amico è dichiarata dalla classe che sta concedendo l'accesso. La dichiarazione amico può essere posizionata ovunque nella dichiarazione della classe. Non è influenzato dalle parole chiave di controllo degli accessi.
#include <iostream> using namespace std; class Point { friend void ChangePrivate( Point & ); public: Point( void ) : m_i(0) {} void PrintPrivate( void ){cout << m_i << endl; } private: int m_i; }; void ChangePrivate ( Point &i ) { i.m_i++; } int main() { Point sPoint; sPoint.PrintPrivate(); ChangePrivate(sPoint); sPoint.PrintPrivate(); // Output: 0 1 }
I membri della classe come amici
class B;
class A {
public:
int Func1( B& b );
private:
int Func2( B& b );
};
class B {
private:
int _b;
// A::Func1 is a friend function to class B
// so A::Func1 has access to all members of B
friend int A::Func1( B& );
};
int A::Func1( B& b ) { return b._b; } // OK
int A::Func2( B& b ) { return b._b; } // C2248