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:

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

  1. 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
    }
    
C ++ 11
  1. 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

C ++ 11
  1. 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 che bar() non possa propagare un'eccezione non è stato esplicitamente specificato.

  2. 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 e f6 non possono propagare eccezioni. (Anche se un'eccezione può essere generata durante l'esecuzione di f6 , viene catturata e non è consentita la propagazione fuori dalla funzione.) Abbiamo dichiarato che f2 può propagare un'eccezione. Quando l' noexcept è omesso, è equivalente a noexcept(false) , quindi abbiamo implicitamente dichiarato che f1 e f3 possono propagare eccezioni, anche se non possono essere generate eccezioni durante l'esecuzione di f3 .

C ++ 17

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

  1. 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 modello T , quindi per denominare il tipo di type nidificato, è necessario prefissare l'intero nome qualificato con typename . 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;
    
  2. 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;
    } 
    
C ++ 17
  1. typename può anche essere usato quando si dichiara un parametro template template , che precede il nome del parametro, proprio come la class .

    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, incluso void .
  • Se sizeof è applicato a un tipo di riferimento T& oa T&& , è equivalente a sizeof(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'espressione sizeof non può mai avere un valore pari a 0. Vedere il layout dei tipi di oggetto per ulteriori dettagli.
  • I char , signed char e unsigned char hanno una dimensione pari a 1. Al contrario, un byte è definito come la quantità di memoria richiesta per memorizzare un oggetto char . Non significa necessariamente 8 bit, poiché alcuni sistemi hanno oggetti char 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
C ++ 11

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 ++

  1. 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".

  2. 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.

  3. 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

  1. Un qualificatore di tipo che è possibile utilizzare per dichiarare che un oggetto può essere modificato nel programma dall'hardware.

    volatile declarator ;
    

C ++ virtuale

  1. 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

  1. specificatori di testo Specifica il tipo di ritorno della funzione membro virtuale.

  2. membro-funzione-dichiaratore Dichiara una funzione membro.

  3. access-specificatore Definisce il livello di accesso alla classe base, pubblica, protetta o privata. Può apparire prima o dopo la parola chiave virtuale.

  4. nome-classe-base Identifica un tipo di classe precedentemente dichiarato

questo puntatore

  1. 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 ++)

  1. Per implementare la gestione delle eccezioni in C ++, usate try, throw e catch espressioni.
  2. Innanzitutto, utilizzare un blocco try per racchiudere una o più istruzioni che potrebbero generare un'eccezione.
  3. 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.
  4. 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 ++)

  1. 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.

  2. 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

  1. 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.

  2. 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.

  3. 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  


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow