Buscar..


Introducción

Las palabras clave tienen un significado fijo definido por el estándar C ++ y no se pueden utilizar como identificadores. Es ilegal redefinir palabras clave utilizando el preprocesador en cualquier unidad de traducción que incluya un encabezado de biblioteca estándar. Sin embargo, las palabras clave pierden su significado especial dentro de los atributos.

Sintaxis

  • asm ( cadena-literal );
  • noexcept ( expresión ) // significado 1
  • noexcept ( expresión constante ) // significado 2
  • noexcept // significado 2
  • tamaño de la expresión unaria
  • sizeof ( type-id )
  • sizeof ... ( identificador ) // desde C ++ 11
  • nombre de archivo identificador de nombre anidado identificador // que significa 1
  • nombre de archivo plantilla de especificador de nombre anidado ( opt ) simple-template-id // que significa 1
  • identificador de nombre de tipo ( opt ) // significado 2
  • typename ... identifier ( opt ) // significado 2; desde C ++ 11
  • identificador de nombre de tipo ( opt ) = ID de tipo // significado 2
  • plantilla < plantilla-lista-parámetro > nombre tipográfico ... ( opt ) identificador ( opt ) // significado 3
  • plantilla < plantilla-lista-parámetro > identificador de nombre de tipo ( opt ) = id-expresión // significado 3

Observaciones

La lista completa de palabras clave es la siguiente:

Los tokens final y override no son palabras clave. Pueden usarse como identificadores y tienen un significado especial solo en ciertos contextos.

Los tokens and , and_eq , bitand , bitor , compl , not , not_eq , or , or_eq , xor y xor_eq son ortografías alternativas de && , &= , & , | , ~ ! , != , || , |= , ^ , y ^= , respectivamente. La norma no los trata como palabras clave, pero son palabras clave para todos los propósitos y propósitos, ya que es imposible redefinirlas o usarlas para significar otra cosa que no sean los operadores que representan.

Los siguientes temas contienen explicaciones detalladas de muchas de las palabras clave en C ++, que sirven para propósitos fundamentales como nombrar tipos básicos o controlar el flujo de ejecución.

asm

La palabra clave asm toma un solo operando, que debe ser una cadena literal. Tiene un significado definido por la implementación, pero generalmente se pasa al ensamblador de la implementación, con la salida del ensamblador incorporada en la unidad de traducción.

La declaración asm es una definición , no una expresión , por lo que puede aparecer en el ámbito del bloque o en el ámbito del espacio de nombres (incluido el ámbito global). Sin embargo, dado que el ensamblaje en línea no puede estar limitado por las reglas del lenguaje C ++, asm puede no aparecer dentro de una función constexpr .

Ejemplo:

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

explícito

  1. Cuando se aplica a un constructor de un solo argumento, evita que ese constructor se use para realizar conversiones implícitas.

    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
    

    Desde que C ++ 11 introdujo las listas de inicializadores, en C ++ 11 y posteriores, explicit puede aplicar explicit a un constructor con cualquier número de argumentos, con el mismo significado que en el caso de un solo argumento.

    struct S {
        explicit S(int x, int y);
    };
    S f() {
        return {12, 34};  // ill-formed
        return S{12, 34}; // ok
    }
    
C ++ 11
  1. Cuando se aplica a una función de conversión, evita que esa función de conversión se utilice para realizar conversiones implícitas.

    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 operador unario que determina si la evaluación de su operando puede propagar una excepción. Tenga en cuenta que los cuerpos de las funciones llamadas no se examinan, por lo que noexcept puede producir falsos negativos. El operando no es evaluado.

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

    En este ejemplo, aunque bar() nunca puede lanzar una excepción, noexcept(bar()) sigue siendo falso porque el hecho de que bar() no puede propagar una excepción no se ha especificado explícitamente.

  2. Al declarar una función, especifica si la función puede o no propagar una excepción. Solo, declara que la función no puede propagar una excepción. Con un argumento entre paréntesis, declara que la función puede o no puede propagar una excepción dependiendo del valor de verdad del argumento.

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

    En este ejemplo, hemos declarado que f4 , f5 y f6 no pueden propagar excepciones. (Aunque se puede lanzar una excepción durante la ejecución de f6 , se captura y no se permite que se propague fuera de la función). Hemos declarado que f2 puede propagar una excepción. Cuando se omite el especificador noexcept , es equivalente a noexcept(false) , por lo que hemos declarado implícitamente que f1 y f3 pueden propagar excepciones, incluso aunque las excepciones no se puedan lanzar durante la ejecución de f3 .

C ++ 17

Si una función es o no una noexcept es parte del tipo de función: es decir, en el ejemplo anterior, f1 , f2 y f3 tienen diferentes tipos de f4 , f5 y f6 . Por lo tanto, noexcept también es significativo en punteros de función, argumentos de plantilla, etc.

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

escribe un nombre

  1. Cuando le sigue un nombre calificado, typename especifica que es el nombre de un tipo. Esto suele ser necesario en las plantillas, en particular, cuando el especificador de nombre anidado es un tipo dependiente distinto de la instanciación actual. En este ejemplo, std::decay<T> depende del parámetro de plantilla T , por lo tanto, para nombrar el tipo de type anidado, debemos prefijar todo el nombre calificado con typename . Para más detalles, vea ¿Dónde y por qué tengo que colocar las palabras clave "plantilla" y "nombre de tipo"?

    template <class T>
    auto decay_copy(T&& r) -> typename std::decay<T>::type;
    
  2. Introduce un parámetro de tipo en la declaración de una plantilla . En este contexto, es intercambiable con class .

    template <typename T>
    const T& min(const T& x, const T& y) {
        return b < a ? b : a;
    } 
    
C ++ 17
  1. typename también se puede utilizar al declarar un parámetro de plantilla de plantilla , antes del nombre del parámetro, al igual que la class .

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

tamaño de

Un operador unario que produce el tamaño en bytes de su operando, que puede ser una expresión o un tipo. Si el operando es una expresión, no se evalúa. El tamaño es una expresión constante de tipo std::size_t .

Si el operando es un tipo, debe estar entre paréntesis.

  • Es ilegal aplicar sizeof a un tipo de función.
  • Es ilegal aplicar sizeof a un tipo incompleto, incluido el void .
  • Si se aplica sizeof a un tipo de referencia T& o T&& , es equivalente a sizeof(T) .
  • Cuando se aplica sizeof a un tipo de clase, produce el número de bytes en un objeto completo de ese tipo, incluidos los bytes de relleno en el medio o al final. Por lo tanto, una expresión sizeof nunca puede tener un valor de 0. Consulte el diseño de los tipos de objeto para obtener más detalles.
  • Los tipos char , signed char y unsigned char tienen un tamaño de 1. A la inversa, un byte se define como la cantidad de memoria necesaria para almacenar un objeto char . No significa necesariamente 8 bits, ya que algunos sistemas tienen objetos de char más de 8 bits.

Si expr es una expresión, sizeof( expr ) es equivalente a sizeof(T) donde T es el tipo de 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

El operador sizeof... produce el número de elementos en un paquete de parámetros.

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

Diferentes palabras clave

vacío C ++

  1. Cuando se utiliza como un tipo de retorno de función, la palabra clave void especifica que la función no devuelve un valor. Cuando se usa para la lista de parámetros de una función, void especifica que la función no toma parámetros. Cuando se usa en la declaración de un puntero, void especifica que el puntero es "universal".

  2. Si el tipo de un puntero es nulo *, el puntero puede apuntar a cualquier variable que no esté declarada con la palabra clave constante o volátil. Un puntero de vacío no se puede anular a menos que se convierta a otro tipo. Un puntero vacío se puede convertir en cualquier otro tipo de puntero de datos.

  3. Un puntero de vacío puede apuntar a una función, pero no a un miembro de clase en 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 ++ volátil

  1. Un calificador de tipo que puede usar para declarar que un objeto puede ser modificado en el programa por el hardware.

    volatile declarator ;
    

C ++ virtual

  1. La palabra clave virtual declara una función virtual o una clase base virtual.

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

Parámetros

  1. especificadores de tipo Especifica el tipo de retorno de la función miembro virtual.

  2. miembro-función-declarador Declara una función miembro.

  3. especificador de acceso Define el nivel de acceso a la clase base, público, protegido o privado. Puede aparecer antes o después de la palabra clave virtual.

  4. nombre-clase-base identifica un tipo de clase previamente declarado

este puntero

  1. El puntero de este es un puntero accesible solo dentro de las funciones miembro no estáticas de una clase, estructura o tipo de unión. Apunta al objeto para el que se llama la función miembro. Las funciones miembro estáticas no tienen este puntero.

    this->member-identifier  
    

Un puntero de este objeto no es parte del objeto en sí; no se refleja en el resultado de una sentencia sizeof en el objeto. En cambio, cuando se llama a una función miembro no estática para un objeto, el compilador pasa la dirección del objeto como un argumento oculto a la función. Por ejemplo, la siguiente llamada de función:

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 

Intentar, lanzar y atrapar declaraciones (C ++)

  1. Para implementar el manejo de excepciones en C ++, use las expresiones try, throw y catch.
  2. Primero, use un bloque de prueba para encerrar una o más declaraciones que puedan generar una excepción.
  3. Una expresión de lanzamiento indica que se ha producido una condición excepcional (a menudo, un error) en un bloque try. Puede usar un objeto de cualquier tipo como el operando de una expresión de lanzamiento. Normalmente, este objeto se utiliza para comunicar información sobre el error. En la mayoría de los casos, recomendamos que use la clase std :: exception o una de las clases derivadas que se definen en la biblioteca estándar. Si uno de ellos no es apropiado, le recomendamos que obtenga su propia clase de excepción de std :: exception.
  4. Para manejar las excepciones que pueden ser lanzadas, implemente uno o más bloques catch inmediatamente después de un bloque try. Cada bloque catch especifica el tipo de excepción que puede manejar.
    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");   
   // ...  
}

El código después de la cláusula de prueba es la sección protegida del código. La expresión de lanzamiento arroja, es decir, plantea, una excepción. El bloque de código después de la cláusula catch es el controlador de excepciones. Este es el controlador que captura la excepción que se produce si los tipos en las expresiones de lanzamiento y captura son compatibles.

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

amigo (C ++)

  1. En algunas circunstancias, es más conveniente otorgar acceso de nivel de miembro a funciones que no son miembros de una clase o a todos los miembros de una clase separada. Sólo el implementador de la clase puede declarar quiénes son sus amigos. Una función o clase no puede declararse como un amigo de ninguna clase. En una definición de clase, use la palabra clave friend y el nombre de una función que no sea miembro u otra clase para otorgarle acceso a los miembros privados y protegidos de su clase. En una definición de plantilla, un parámetro de tipo se puede declarar como amigo.

  2. Si declara una función de amigo que no se había declarado previamente, esa función se exporta al ámbito no clasificador adjunto.

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

funciones de amigo

  1. Una función amiga es una función que no es miembro de una clase pero tiene acceso a los miembros privados y protegidos de la clase. Las funciones del amigo no se consideran miembros de la clase; Son funciones externas normales que tienen privilegios de acceso especiales.

  2. Los amigos no están dentro del alcance de la clase, y no se les llama mediante los operadores de selección de miembros (. Y ->) a menos que sean miembros de otra clase.

  3. La clase que otorga acceso declara una función de amigo. La declaración de amigo se puede colocar en cualquier parte de la declaración de clase. No se ve afectado por las palabras clave de control de acceso.

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

Miembros de la clase como amigos

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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow