Suche…


Einführung

Schlüsselwörter haben eine durch den C ++ - Standard definierte feste Bedeutung und können nicht als Bezeichner verwendet werden. Es ist nicht zulässig, Schlüsselwörter mithilfe des Präprozessors in einer Übersetzungseinheit neu zu definieren, die einen Standard-Bibliothekskopf enthält. Schlüsselwörter verlieren jedoch ihre besondere Bedeutung in Attributen.

Syntax

  • asm ( String-Literal );
  • noexcept ( Ausdruck ) // Bedeutung 1
  • noexcept ( konstanter Ausdruck ) // Bedeutung 2
  • noexcept // bedeutung 2
  • sizeof unary-expression
  • sizeof ( Typ-ID )
  • sizeof ... ( Bezeichner ) // seit C ++ 11
  • Type - Name verschachtelt-name-Bezeichner Kennung // 1 Bedeutung
  • Typname Vorlage für geschachtelte Namen (optional) ( opt ) simple-template-id // Bedeutung 1
  • Typname Kennung (opt) // Bedeutung 2
  • Typname ... Bezeichner ( Opt ) // Bedeutung 2; seit C ++ 11
  • Bezeichner Typname ( opt ) = Typ-ID // Bedeutung 2
  • template < template-parameter-list > typename ... ( opt ) Bezeichner ( opt ) // Bedeutung 3
  • template <template-Parameter-Liste> Typname Kennung (opt) = id-Ausdruck // Bedeutung 3

Bemerkungen

Die vollständige Liste der Keywords lautet wie folgt:

Das Token final und override sind keine Schlüsselwörter. Sie können als Bezeichner verwendet werden und haben nur in bestimmten Zusammenhängen eine besondere Bedeutung.

Die Token and , and_eq , bitand , bitor , compl , not , not_eq or or_eq , xor und xor_eq sind alternative Schreibweisen von && , &= , & , | , ~ ! , != , || , |= , ^ und ^= . Der Standard behandelt sie nicht als Schlüsselwörter, aber sie sind Schlüsselwörter für alle Absichten und Zwecke, da es unmöglich ist, sie neu zu definieren oder sie zu verwenden, um etwas anderes als die von ihnen repräsentierten Operatoren zu bedeuten.

Die folgenden Themen enthalten ausführliche Erklärungen zu vielen Schlüsselwörtern in C ++, die grundlegenden Zwecken dienen, z. B. zum Benennen von Basistypen oder zum Steuern des Ausführungsflusses.

asm

Das Schlüsselwort asm akzeptiert einen einzelnen Operanden, der ein String-Literal sein muss. Es hat eine implementierungsdefinierte Bedeutung, wird jedoch normalerweise an den Assembler der Implementierung übergeben, wobei die Ausgabe des Assemblers in die Übersetzungseinheit integriert wird.

Die asm Anweisung ist eine Definition und kein Ausdruck . Daher kann sie entweder im Blockbereich oder im Namespace-Bereich (einschließlich des globalen Bereichs) stehen. Da die Inline-Assembly jedoch nicht durch die Regeln der C ++ - Sprache eingeschränkt werden kann, erscheint asm möglicherweise nicht in einer constexpr Funktion.

Beispiel:

[[noreturn]] void halt_system() {
    asm("hlt");
}

explizit

  1. Bei Anwendung auf einen Konstruktor mit einem einzigen Argument wird verhindert, dass dieser Konstruktor für implizite Konvertierungen verwendet wird.

    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
    

    Seit C ++ 11 Initializer-Listen eingeführt hat, kann explicit in C ++ 11 und höher auf einen Konstruktor mit einer beliebigen Anzahl von Argumenten angewendet werden, die dieselbe Bedeutung haben wie im Fall eines einzelnen Arguments.

    struct S {
        explicit S(int x, int y);
    };
    S f() {
        return {12, 34};  // ill-formed
        return S{12, 34}; // ok
    }
    
C ++ 11
  1. Bei Anwendung auf eine Konvertierungsfunktion wird verhindert, dass diese Konvertierungsfunktion für implizite Konvertierungen verwendet wird.

    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. Ein unärer Operator, der bestimmt, ob die Auswertung seines Operanden eine Ausnahme auslösen kann. Beachten Sie, dass die Körper der aufgerufenen Funktionen nicht untersucht werden, sodass noexcept falsche Negative noexcept kann. Der Operand wird nicht ausgewertet.

    #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
    }
    

    Auch wenn bar() niemals eine Ausnahme noexcept(bar()) kann, ist noexcept(bar()) immer noch falsch, da die Tatsache, dass bar() keine Ausnahme noexcept(bar()) kann, nicht explizit angegeben wurde.

  2. Gibt bei der Deklaration einer Funktion an, ob die Funktion eine Ausnahme weitergeben kann. Allein erklärt es, dass die Funktion keine Ausnahme weitergeben kann. Mit einem Argument in Klammern erklärt es, dass die Funktion abhängig vom Wahrheitswert des Arguments eine Ausnahme ausgeben kann oder nicht.

    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 diesem Beispiel haben wir erklärt, dass f4 , f5 und f6 keine Ausnahmen verbreiten können. (Obwohl eine Ausnahme während der Ausführung von f6 ausgelöst werden kann, wird sie abgefangen und darf sich nicht aus der Funktion ausbreiten.) Wir haben erklärt, dass f2 eine Ausnahme f2 kann. Wenn der noexcept weggelassen wird, entspricht er noexcept(false) haben wir implizit erklärt, dass f1 und f3 Ausnahmen ausbreiten können, obwohl Ausnahmen während der Ausführung von f3 nicht wirklich ausgelöst werden können.

C ++ 17

Ob eine Funktion keine noexcept ist oder nicht, ist Teil des Funktionstyps: Im obigen Beispiel unterscheiden sich f1 , f2 und f3 von f4 , f5 und f6 . Daher ist noexcept auch für Funktionszeiger, Vorlagenargumente usw. von Bedeutung.

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

Modellname

  1. Wenn er von einem qualifizierten Namen gefolgt wird, gibt typename an, dass es sich um den Namen eines Typs handelt. Dies ist häufig in Vorlagen erforderlich, insbesondere wenn der geschachtelte Namensbezeichner ein von der aktuellen Instanziierung abweichender Typ ist. In diesem Beispiel std::decay<T> ist abhängig von dem Template - Parametern T , so um den verschachtelte Art zu nennen type , wir die gesamten qualifizierten Namen mit Präfix müssen typename . Weitere Informationen finden Sie unter Wo und warum muss ich die Schlüsselwörter "template" und "typename" eingeben?

    template <class T>
    auto decay_copy(T&& r) -> typename std::decay<T>::type;
    
  2. Führt einen Typparameter in die Deklaration einer Vorlage ein . In diesem Zusammenhang ist es mit der class austauschbar.

    template <typename T>
    const T& min(const T& x, const T& y) {
        return b < a ? b : a;
    } 
    
C ++ 17
  1. typename kann auch verwendet werden, wenn ein template-Template-Parameter deklariert wird , der wie der class dem Namen des Parameters vorangeht.

    template <template <class T> typename U>
    void f() {
        U<int>::do_it();
        U<double>::do_it();
    }
    

Größe von

Ein unärer Operator, der die Größe seines Operanden in Bytes ermittelt, der entweder ein Ausdruck oder ein Typ sein kann. Wenn der Operand ein Ausdruck ist, wird er nicht ausgewertet. Die Größe ist ein konstanter Ausdruck des Typs std::size_t .

Wenn der Operand ein Typ ist, muss er in Klammern gesetzt werden.

  • Es ist nicht sizeof , sizeof auf einen Funktionstyp anzuwenden.
  • Es ist nicht sizeof , sizeof auf einen unvollständigen Typ, einschließlich void , anzuwenden.
  • Wenn sizeof auf einen Referenztyp T& oder T&& angewendet wird, entspricht es sizeof(T) .
  • Wenn sizeof auf einen Klassentyp angewendet wird, gibt es die Anzahl der Bytes in einem vollständigen Objekt dieses Typs an, einschließlich der Auffüllbytes in der Mitte oder am Ende. Daher kann ein sizeof Ausdruck niemals den Wert 0 haben. Weitere Informationen finden Sie im Layout der Objekttypen .
  • Die Typen char , signed char und unsigned char haben eine Größe von 1. Umgekehrt wird ein Byte als die Menge Speicher definiert, die zum Speichern eines char Objekts erforderlich ist. Es muss nicht unbedingt 8 Bit bedeuten, da einige Systeme haben char Objekte länger als 8 Bit.

Wenn expr ein Ausdruck ist, ist sizeof( expr ) äquivalent zu sizeof(T) wobei T der Typ von expr ist.

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

Der Operator sizeof... gibt die Anzahl der Elemente in einem Parameterpaket an.

template <class... T>
void f(T&&...) {
    std::cout << "f was called with " << sizeof...(T) << " arguments\n";
}

Unterschiedliche Schlüsselwörter

C ++ ungültig machen

  1. Bei Verwendung als Funktionsrückgabetyp gibt das Schlüsselwort void an, dass die Funktion keinen Wert zurückgibt. Wenn void für die Parameterliste einer Funktion verwendet wird, gibt void an, dass die Funktion keine Parameter annimmt. Bei der Deklaration eines Zeigers gibt void an, dass der Zeiger "universal" ist.

  2. Wenn der Zeigertyp void * ist, kann der Zeiger auf eine beliebige Variable zeigen, die nicht mit dem Schlüsselwort const oder volatile deklariert ist. Ein ungültiger Zeiger kann nicht dereferenziert werden, wenn er nicht in einen anderen Typ umgewandelt wird. Ein ungültiger Zeiger kann in einen beliebigen anderen Datenzeiger-Typ umgewandelt werden.

  3. Ein ungültiger Zeiger kann auf eine Funktion zeigen, aber nicht auf ein Klassenmitglied 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;  
    

Flüchtiges C ++

  1. Ein Typqualifizierer, mit dem Sie angeben können, dass ein Objekt im Programm von der Hardware geändert werden kann.

    volatile declarator ;
    

virtuelles C ++

  1. Das virtuelle Schlüsselwort deklariert eine virtuelle Funktion oder eine virtuelle Basisklasse.

    virtual [type-specifiers] member-function-declarator  
    virtual [access-specifier] base-class-name 
    

Parameter

  1. Typspezifizierer Gibt den Rückgabetyp der virtuellen Memberfunktion an.

  2. member-function-declarator Deklariert eine Member-Funktion.

  3. Zugriffsspezifizierer Definiert die Zugriffsebene für die Basisklasse (öffentlich, geschützt oder privat). Kann vor oder nach dem virtuellen Schlüsselwort angezeigt werden.

  4. Basisklassenname Gibt einen zuvor deklarierten Klassentyp an

dieser Zeiger

  1. Dieser Zeiger ist ein Zeiger, auf den nur innerhalb der nicht statischen Memberfunktionen einer Klasse, Struktur oder eines Unionstyps zugegriffen werden kann. Es zeigt auf das Objekt, für das die Memberfunktion aufgerufen wird. Statische Memberfunktionen haben diesen Zeiger nicht.

    this->member-identifier  
    

Der Zeiger eines Objekts ist nicht Teil des Objekts selbst; Sie wird nicht im Ergebnis einer Anweisung sizeof für das Objekt berücksichtigt. Wenn stattdessen eine nicht statische Member-Funktion für ein Objekt aufgerufen wird, wird die Adresse des Objekts vom Compiler als verstecktes Argument an die Funktion übergeben. Zum Beispiel den folgenden Funktionsaufruf:

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 

Anweisungen versuchen, werfen und abfangen (C ++)

  1. Um die Ausnahmebehandlung in C ++ zu implementieren, verwenden Sie try, throw und catch-Ausdrücke.
  2. Verwenden Sie zunächst einen try-Block, um eine oder mehrere Anweisungen einzuschließen, die eine Ausnahme auslösen können.
  3. Ein Wurfausdruck signalisiert, dass in einem try-Block eine außergewöhnliche Bedingung - oft ein Fehler - aufgetreten ist. Sie können ein Objekt eines beliebigen Typs als Operanden eines Wurfausdrucks verwenden. Normalerweise wird dieses Objekt verwendet, um Informationen zu dem Fehler zu übermitteln. In den meisten Fällen wird empfohlen, die std :: ausnahmeklasse oder eine der abgeleiteten Klassen zu verwenden, die in der Standardbibliothek definiert sind. Wenn eine davon nicht geeignet ist, empfehlen wir Ihnen, Ihre eigene Exception-Klasse von std :: exception abzuleiten.
  4. Implementieren Sie einen oder mehrere catch-Blöcke unmittelbar nach einem try-Block, um möglicherweise ausgelöste Ausnahmen zu behandeln. Jeder catch-Block gibt den Typ der Ausnahme an, die er behandeln kann.
    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");   
   // ...  
}

Der Code nach der try-Klausel ist der überwachte Codeabschnitt. Der Wurfausdruck wirft - das heißt, löst eine Ausnahme aus. Der Codeblock nach der catch-Klausel ist der Ausnahmehandler. Dies ist der Handler, der die Ausnahme abfängt, die ausgelöst wird, wenn die Typen in den Wurf- und Fangausdrücken kompatibel sind.

    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;  
}

Freund (C ++)

  1. Unter bestimmten Umständen ist es günstiger, auf Mitgliedsebene Zugriff auf Funktionen zu gewähren, die keine Mitglieder einer Klasse sind, oder auf alle Mitglieder einer separaten Klasse. Nur der Klassenimplementierer kann angeben, wer seine Freunde sind. Eine Funktion oder Klasse kann sich nicht als Freund einer Klasse deklarieren. Verwenden Sie in einer Klassendefinition das Schlüsselwort friend und den Namen einer Nichtmitgliedsfunktion oder einer anderen Klasse, um diesem Zugriff auf die privaten und geschützten Mitglieder Ihrer Klasse zu gewähren. In einer Vorlagendefinition kann ein Typparameter als Freund deklariert werden.

  2. Wenn Sie eine Friend-Funktion deklarieren, die zuvor nicht deklariert wurde, wird diese Funktion in den umschließenden nicht-Klassenbereich exportiert.

    class friend F  
    friend F;
    class ForwardDeclared;// Class name is known.  
    class HasFriends  
    {  
       friend int ForwardDeclared::IsAFriend();// C2039 error expected  
    };  
    

Freundesfunktionen

  1. Eine Friend-Funktion ist eine Funktion, die kein Mitglied einer Klasse ist, aber Zugriff auf die privaten und geschützten Member der Klasse hat. Freunde-Funktionen werden nicht als Klassenmitglieder betrachtet. Es handelt sich hierbei um normale externe Funktionen, die über spezielle Zugriffsrechte verfügen.

  2. Freunde sind nicht im Gültigkeitsbereich der Klasse und werden nicht mit den Elementauswahloperatoren (. Und ->) aufgerufen, es sei denn, sie sind Mitglieder einer anderen Klasse.

  3. Eine Friend-Funktion wird von der Klasse deklariert, die den Zugriff gewährt. Die Friend-Deklaration kann an beliebiger Stelle in der Klassendeklaration platziert werden. Es ist von den Schlüsselwörtern für die Zugriffskontrolle nicht betroffen.

    #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  
    }  
    

Klassenmitglieder als Freunde

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow