C++: явное ключевое слово

Явное ключевое слово в C++ может использоваться только для изменения конструктора класса только с одним параметром.Его функция состоит в том, чтобы указать, что конструктор является явным, а не неявным.Другое ключевое слово, соответствующее ему, является неявным, то есть скрыт, конструктор класса объявлен как неявное по умолчанию.

Итак, в чем разница между явно объявленным конструктором и неявно объявленным?Давайте рассмотрим следующий пример:

class CxString  // 没有使用explicit关键字的类声明, 即默认为隐式声明  
{  
public:  
    char *_pstr;  
    int _size;  
    CxString(int size)  
    {  
        _size = size;                // string的预设大小  
        _pstr = malloc(size + 1);    // 分配string的内存  
        memset(_pstr, 0, size + 1);  
    }  
    CxString(const char *p)  
    {  
        int size = strlen(p);  
        _pstr = malloc(size + 1);    // 分配string的内存  
        strcpy(_pstr, p);            // 复制字符串  
        _size = strlen(_pstr);  
    }  
    // 析构函数这里不讨论, 省略...  
};  
  
    // 下面是调用:  
    CxString string1(24);     // 这样是OK的, 为CxString预分配24字节的大小的内存  
    CxString string2 = 10;    // 这样是OK的, 为CxString预分配10字节的大小的内存  
    CxString string3;         // 这样是不行的, 因为没有默认构造函数, 错误为: “CxString”: 没有合适的默认构造函数可用  
    CxString string4("aaaa"); // 这样是OK的  
    CxString string5 = "bbb"; // 这样也是OK的, 调用的是CxString(const char *p)  
    CxString string6 = 'c';   // 这样也是OK的, 其实调用的是CxString(int size), 且size等于'c'的ascii码  
    string1 = 2;              // 这样也是OK的, 为CxString预分配2字节的大小的内存  
    string2 = 3;              // 这样也是OK的, 为CxString预分配3字节的大小的内存  
    string3 = string1;        // 这样也是OK的, 至少编译是没问题的, free释放_pstr内存指针的时候可能会报错, 完整的代码必须重载运算符"=", 并在其中处理内存释放

вставьте сюда описание изображения

Почему в приведенном выше коде возможно предложение «CxString string2 = 10;»?

В C++, если конструктор имеет только один параметр, то во время компиляции будет выполняться операция преобразования по умолчанию: преобразовать данные, соответствующие типу данных конструктора, в объект этого класса. То есть в коде «CxString string2 = 10;» компилятор автоматически преобразует целое число в объект класса CxString, что фактически эквивалентно следующей операции:

CxString string2(10);  
// 或如下代码
CxString temp(10);  
CxString string2 = temp;  

Однако _size в приведенном выше коде представляет собой размер выделяемой строковой памяти, поэтому второе предложение вызова «CxString string2 = 10;» и шестое предложение «CxString string6 = 'c';» кажутся неописуемыми, и это легко быть в замешательстве. Есть ли способ предотвратить это использование? Ответ заключается в использовании явного ключевого слова. Давайте изменим приведенный выше код следующим образом:

class CxString  // 使用关键字explicit的类声明, 显示转换  
{
    
      
public:  
    char *_pstr;  
    int _size;  
    explicit CxString(int size)  
    {
    
      
        _size = size;  
        // 代码同上, 省略...  
    }  
    CxString(const char *p)  
    {
    
      
        // 代码同上, 省略...  
    }  
};  
  
    // 下面是调用:  
    CxString string1(24);     // 这样是OK的  
    CxString string2 = 10;    // 这样是不行的, 因为explicit关键字取消了隐式转换  
    CxString string3;         // 这样是不行的, 因为没有默认构造函数  
    CxString string4("aaaa"); // 这样是OK的  
    CxString string5 = "bbb"; // 这样也是OK的, 调用的是CxString(const char *p)  
    CxString string6 = 'c';   // 这样是不行的, 其实调用的是CxString(int size), 且size等于'c'的ascii码, 但explicit关键字取消了隐式转换  
    string1 = 2;              // 这样也是不行的, 因为取消了隐式转换  
    string2 = 3;              // 这样也是不行的, 因为取消了隐式转换  
    string3 = string1;        // 这样也是不行的, 因为取消了隐式转换, 除非类实现操作符"="的重载 

вставьте сюда описание изображения

Роль явного ключевого слова состоит в том, чтобы предотвратить неявное автоматическое преобразование конструктора класса.

Как упоминалось выше, явное ключевое слово допустимо только для конструкторов класса с одним параметром.Если параметры конструктора класса больше или равны двум, неявное преобразование не произойдет, поэтому явное ключевое слово недопустимо. Например:

class CxString  // explicit关键字在类构造函数参数大于或等于两个时无效  
{
    
      
public:  
    char *_pstr;  
    int _age;  
    int _size;  
    explicit CxString(int age, int size)  
    {
    
      
        _age = age;  
        _size = size;  
        // 代码同上, 省略...  
    }  
    CxString(const char *p)  
    {
    
      
        // 代码同上, 省略...  
    }  
};  
  
    // 这个时候有没有explicit关键字都是一样的  

Однако есть исключение, то есть, когда все параметры, кроме первого параметра, имеют значения по умолчанию, явное ключевое слово все еще действует.В это время при вызове конструктора передается только один параметр, что эквивалентно только одному параметру Конструктор класса примера выглядит следующим образом:

class CxString  // 使用关键字explicit声明  
{
    
      
public:  
    int _age;  
    int _size;  
    explicit CxString(int age, int size = 0)  
    {
    
      
        _age = age;  
        _size = size;  
        // 代码同上, 省略...  
    }  
    CxString(const char *p)  
    {
    
      
        // 代码同上, 省略...  
    }  
};  
  
    // 下面是调用:  
    CxString string1(24);     // 这样是OK的  
    CxString string2 = 10;    // 这样是不行的, 因为explicit关键字取消了隐式转换  
    CxString string3;         // 这样是不行的, 因为没有默认构造函数  
    string1 = 2;              // 这样也是不行的, 因为取消了隐式转换  
    string2 = 3;              // 这样也是不行的, 因为取消了隐式转换  
    string3 = string1;        // 这样也是不行的, 因为取消了隐式转换, 除非类实现操作符"="的重载

Резюме:
ключевое слово absolute нужно использовать только перед конструктором с одним аргументом в классе. Поскольку конструкторы без аргументов и конструкторы с несколькими аргументами всегда вызываются явно, в этом случае бессмысленно добавлять явное значение перед конструктором.

В спецификации Google C++ упоминается: преимущество явного метода заключается в том, что он позволяет избежать несвоевременных преобразований типов, а недостатков нет. Поэтому Google соглашается с тем, что все конструкторы с одним параметром должны отображаться.Есть только несколько случаев, когда конструктор копирования не может быть объявлен явным, например, класс, который является прозрачной оболочкой для других классов.
Эффективный C++ сказал: Конструкторы, объявленные как явные, обычно более популярны, чем их неявные собратья. Потому что они запрещают компилятору выполнять непреднамеренные (и часто непреднамеренные) преобразования типов. Если у меня нет веской причины разрешить использование конструктора для неявных преобразований типов, я объявлю его явным и призываю всех следовать той же политике.

Supongo que te gusta

Origin blog.csdn.net/crossoverpptx/article/details/129861992
Recomendado
Clasificación