Szukaj…


Wprowadzenie

Słowa kluczowe mają ustalone znaczenie zdefiniowane przez standard C ++ i nie mogą być używane jako identyfikatory. Redefiniowanie słów kluczowych przy użyciu preprocesora w dowolnej jednostce tłumaczeniowej zawierającej standardowy nagłówek biblioteki jest nielegalne. Jednak słowa kluczowe tracą swoje specjalne znaczenie w atrybutach.

Składnia

  • asm ( literał-ciąg );
  • noexcept ( wyrażenie ) // znaczenie 1
  • noexcept ( wyrażenie stałe ) // znaczenie 2
  • noexcept // co oznacza 2
  • wielkość wyrażenia jednoargumentowego
  • sizeof ( identyfikator typu )
  • sizeof ... ( identyfikator ) // od C ++ 11
  • typename identyfikator zagnieżdżony-nazwa- identyfikator // znaczenie 1
  • typename nested-name-specifier template ( opt ) simple-template-id // znaczenie 1
  • identyfikator nazwy typu ( opt ) // znaczenie 2
  • typename ... identyfikator ( opt ) // znaczenie 2; od C ++ 11
  • identyfikator nazwy typu ( opt ) = identyfikator typu // znaczenie 2
  • szablon < lista-parametrów-listy > nazwa_typu ... ( opt ) identyfikator ( opt ) // znaczenie 3
  • szablon < lista-parametrów-listy > typename identifier ( opt ) = id-wyrażenie // znaczenie 3

Uwagi

Pełna lista słów kluczowych jest następująca:

final i override tokeny nie są słowami kluczowymi. Mogą być używane jako identyfikatory i mają specjalne znaczenie tylko w niektórych kontekstach.

Tokeny and , and_eq , bitand , bitor , compl , not , not_eq , or , or_eq , xor , a xor_eq alternatywne pisowni && , &= , & , | , ~ ! , != , || , |= , ^ i ^= odpowiednio. Standard nie traktuje ich jako słów kluczowych, ale są słowami kluczowymi do wszystkich celów i celów, ponieważ nie można ich przedefiniować ani używać ich w znaczeniu innym niż operatory, które reprezentują.

Poniższe tematy zawierają szczegółowe objaśnienia wielu słów kluczowych w C ++, które służą podstawowym celom, takim jak nazywanie podstawowych typów lub kontrolowanie przebiegu wykonywania.

jako M

asm kluczowe asm przyjmuje pojedynczy operand, który musi być dosłowny. Ma znaczenie zdefiniowane w implementacji, ale zwykle jest przekazywane do asemblera implementacji, a dane wyjściowe asemblera są włączane do jednostki tłumaczącej.

Instrukcja asm jest definicją , a nie wyrażeniem , więc może pojawiać się w zakresie bloków lub w przestrzeni nazw (w tym w zakresie globalnym). Ponieważ jednak zestaw wbudowany nie może być ograniczony regułami języka C ++, asm może nie pojawić się w funkcji constexpr .

Przykład:

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

wyraźny

  1. Po zastosowaniu do konstruktora z jednym argumentem uniemożliwia temu konstruktorowi wykonywanie niejawnych konwersji.

    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
    

    Ponieważ C ++ 11 wprowadził listy inicjalizujące, w C ++ 11 i późniejszych, explicit można zastosować do konstruktora z dowolną liczbą argumentów, o takim samym znaczeniu jak w przypadku pojedynczego argumentu.

    struct S {
        explicit S(int x, int y);
    };
    S f() {
        return {12, 34};  // ill-formed
        return S{12, 34}; // ok
    }
    
C ++ 11
  1. Po zastosowaniu do funkcji konwersji zapobiega wykorzystywaniu tej funkcji konwersji do niejawnych konwersji.

    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
    

nie

C ++ 11
  1. Jednoargumentowy operator, który określa, czy ocena jego operandu może propagować wyjątek. Zauważ, że ciała wywoływanych funkcji nie są badane, więc noexcept może dawać fałszywych negatywów. Operand nie jest oceniany.

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

    W tym przykładzie, mimo że bar() nigdy nie może noexcept(bar()) wyjątku, noexcept(bar()) jest nadal fałszywy, ponieważ fakt, że bar() nie może propagować wyjątku, nie został wyraźnie określony.

  2. Podczas deklarowania funkcji określa, czy funkcja może propagować wyjątek. Sam deklaruje, że funkcja nie może propagować wyjątku. Za pomocą argumentu w nawiasach deklaruje, że funkcja może lub nie może propagować wyjątku w zależności od wartości prawdy argumentu.

    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&) {}
    }
    

    W tym przykładzie zadeklarowaliśmy, że f4 , f5 i f6 nie mogą propagować wyjątków. (Chociaż wyjątek może zostać zgłoszony podczas wykonywania f6 , jest on wychwytywany i nie może się propagować poza funkcją.) Zadeklarowaliśmy, że f2 może propagować wyjątek. Gdy specyfikator noexcept zostanie pominięty, jest to równoważne z noexcept(false) , więc domyślnie zadeklarowaliśmy, że f1 i f3 mogą propagować wyjątki, nawet jeśli wyjątki nie mogą być faktycznie zgłaszane podczas wykonywania f3 .

C ++ 17

To, czy funkcja nie jest noexcept jest częścią typu funkcji: to znaczy w powyższym przykładzie f1 , f2 i f3 mają różne typy od f4 , f5 i f6 . Dlatego noexcept ma również znaczenie w przypadku wskaźników funkcji, argumentów szablonów i tak dalej.

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

Wpisz imię

  1. Po nazwie kwalifikowanej typename określa, że jest to nazwa typu. Jest to często wymagane w szablonach, w szczególności gdy specyfikator zagnieżdżonej nazwy jest typem zależnym innym niż bieżąca instancja. W tym przykładzie, std::decay<T> zależy od szablonu parametr T , tak aby wymienić zagnieżdżony typ type , musimy poprzedzić całą kwalifikowaną nazwę z typename . Aby dowiedzieć się więcej o deatilach, zobacz Gdzie i dlaczego muszę umieszczać słowa kluczowe „szablon” i „typename”?

    template <class T>
    auto decay_copy(T&& r) -> typename std::decay<T>::type;
    
  2. Wprowadza parametr typu do deklaracji szablonu . W tym kontekście jest wymienny z class .

    template <typename T>
    const T& min(const T& x, const T& y) {
        return b < a ? b : a;
    } 
    
C ++ 17
  1. typename może być również używana podczas deklarowania parametru szablonu szablonu , poprzedzającego nazwę parametru, podobnie jak class .

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

rozmiar

Jednoargumentowy operator, który podaje rozmiar w bajtach swojego operandu, który może być wyrażeniem lub typem. Jeśli operand jest wyrażeniem, nie jest analizowane. Rozmiar jest stałym wyrażeniem typu std::size_t .

Jeśli operand jest typem, musi być nawiasowany.

  • Stosowanie sizeof do typu funkcji jest nielegalne.
  • Stosowanie sizeof do niekompletnego typu, w tym void jest niezgodne z prawem.
  • Jeśli sizeof jest zastosowany do typu odniesienia T& lub T&& , jest on równoważny sizeof(T) .
  • Zastosowanie sizeof do typu klasy daje liczbę bajtów w pełnym obiekcie tego typu, w tym bajty wypełniające na środku lub na końcu. Dlatego wyrażenie sizeof nigdy nie może mieć wartości 0. Aby uzyskać więcej informacji, zobacz układ typów obiektów .
  • Typy char , signed char i unsigned char mają rozmiar 1. I odwrotnie, bajt jest definiowany jako ilość pamięci wymaganej do przechowywania obiektu char . Nie musi to oznaczać 8 bitów, ponieważ niektóre systemy mają obiekty char dłuższe niż 8 bitów.

Jeśli wyrażenie jest wyrażeniem, sizeof( wyrażenie ) jest równoważne sizeof(T) gdzie T jest rodzajem wyrażenia.

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

Operator sizeof... zwraca liczbę elementów w pakiecie parametrów.

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

Różne słowa kluczowe

void C ++

  1. Gdy jest używane jako typ zwracany przez funkcję, słowo kluczowe void określa, że funkcja nie zwraca wartości. W przypadku użycia dla listy parametrów funkcji, void określa, że funkcja nie przyjmuje parametrów. W przypadku użycia w deklaracji wskaźnika, void określa, że wskaźnik jest „uniwersalny”.

  2. Jeśli typ wskaźnika jest nieważny *, wskaźnik może wskazywać dowolną zmienną, która nie jest zadeklarowana za pomocą słowa kluczowego const lub volatile. Wskaźnika pustki nie można wyrejestrować, chyba że zostanie on rzutowany na inny typ. Wskaźnik pustki można przekształcić w dowolny inny wskaźnik danych.

  3. Wskaźnik pustki może wskazywać na funkcję, ale nie na element klasy w 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;  
    

Lotny C ++

  1. Kwalifikator typu, którego można użyć do zadeklarowania, że obiekt może być modyfikowany w programie przez sprzęt.

    volatile declarator ;
    

wirtualny C ++

  1. Wirtualne słowo kluczowe deklaruje wirtualną funkcję lub wirtualną klasę podstawową.

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

Parametry

  1. specyfikatory typu Określa typ zwracanej funkcji wirtualnego elementu członkowskiego.

  2. deklarator funkcji członka Deklaruje funkcję członka.

  3. specyfikator dostępu Definiuje poziom dostępu do klasy podstawowej, publicznej, chronionej lub prywatnej. Może pojawić się przed wirtualnym słowem kluczowym lub po nim.

  4. base-class-name Identyfikuje wcześniej zadeklarowany typ klasy

ten wskaźnik

  1. Ten wskaźnik jest wskaźnikiem dostępnym tylko w ramach niestatycznych funkcji składowych typu klasy, struktury lub unii. Wskazuje obiekt, dla którego wywoływana jest funkcja członka. Statyczne funkcje składowe nie mają tego wskaźnika.

    this->member-identifier  
    

Wskaźnik tego obiektu nie jest częścią samego obiektu; nie jest odzwierciedlone w wyniku instrukcji sizeof na obiekcie. Zamiast tego, gdy wywoływana jest niestatyczna funkcja elementu dla obiektu, adres obiektu jest przekazywany przez kompilator jako ukryty argument funkcji. Na przykład następujące wywołanie funkcji:

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 

try, throw i catch Instrukcje (C ++)

  1. Aby zaimplementować obsługę wyjątków w C ++, używasz wyrażeń try, throw i catch.
  2. Najpierw użyj bloku try, aby dołączyć jedną lub więcej instrukcji, które mogą zgłaszać wyjątek.
  3. Wyrażenie wyrzucenia sygnalizuje, że wystąpił wyjątkowy warunek - często błąd - w bloku try. Możesz użyć obiektu dowolnego typu jako argumentu wyrażenia rzutowania. Zazwyczaj ten obiekt służy do przekazywania informacji o błędzie. W większości przypadków zalecamy użycie klasy std :: wyjątek lub jednej z klas pochodnych zdefiniowanych w bibliotece standardowej. Jeśli któryś z nich nie jest odpowiedni, zalecamy wyprowadzenie własnej klasy wyjątków ze std :: wyjątek.
  4. Aby obsłużyć wyjątki, które mogą zostać zgłoszone, zaimplementuj jeden lub więcej bloków catch bezpośrednio po bloku try. Każdy blok catch określa typ wyjątku, który może obsłużyć.
    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");   
   // ...  
}

Kod po klauzuli try jest strzeżoną sekcją kodu. Wyrażenie rzucania rzuca - to znaczy podnosi - wyjątek. Blok kodu po klauzuli catch to moduł obsługi wyjątków. Jest to moduł obsługi, który przechwytuje wyjątek zgłaszany, jeśli typy w wyrażeniach throw i catch są kompatybilne.

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

przyjaciel (C ++)

  1. W niektórych okolicznościach wygodniej jest przyznać dostęp na poziomie członka do funkcji, które nie są członkami klasy lub wszystkim członkom w osobnej klasie. Tylko osoba wdrażająca klasy może zadeklarować, kim są jego przyjaciele. Funkcja lub klasa nie może zadeklarować się jako przyjaciel dowolnej klasy. W definicji klasy użyj słowa kluczowego „przyjaciel” i nazwy funkcji nieczłonkowskiej lub innej klasy, aby przyznać jej dostęp do prywatnych i chronionych członków twojej klasy. W definicji szablonu parametr typu można zadeklarować jako przyjaciela.

  2. Jeśli zadeklarujesz funkcję przyjaciela, która nie została wcześniej zadeklarowana, funkcja ta zostanie wyeksportowana do obejmującego nieklasowego zakresu.

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

funkcje przyjaciela

  1. Funkcja przyjaciela to funkcja, która nie jest członkiem klasy, ale ma dostęp do prywatnych i chronionych członków klasy. Funkcje znajomych nie są uważane za członków klasy; są to normalne funkcje zewnętrzne, które mają specjalne uprawnienia dostępu.

  2. Znajomi nie są objęci zakresem klasy i nie są wywoływani za pomocą operatorów wyboru członków (. I ->), chyba że są członkami innej klasy.

  3. Funkcja znajomego jest deklarowana przez klasę, która udziela dostępu. Deklarację znajomego można umieścić w dowolnym miejscu deklaracji klasy. Nie wpływają na to słowa kluczowe kontroli dostępu.

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

Członkowie klasy jako przyjaciele

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow