文章目录
- 1.C++的隐式对象转换问题
- 举例
- 产生的问题
- 2.使用explicit解决上述问题
- 总结
1.C++的隐式对象转换问题
在C++中,隐式对象转换(Implicit Object Conversion)指的是编译器在不需要程序员明确指示的情况下,自动将对象从一种类型转换为另一种类型的过程。这种转换通常发生在对象被传递给函数或者赋值给另一个对象时。隐式转换可以提高代码的可读性和简洁性,但也可能导致一些不易察觉的错误。
举例
当一个类对象作为参数传递给函数时,编译器可能会使用该类的构造函数来创建一个临时对象,从而实现隐式转换。
考虑一个图书馆管理系统的场景,其中我们有用于处理书籍元数据和用户操作的类。假设有一个类设计用来以整数形式处理用户ID,另一个类设计用来以字符串形式处理书籍的ISBN。
/*UserID类:
构造函数接受一个整数;
id()方法返回该类的id, id的标准格式比如12345
*/
class UserID {
public:UserID(int id) : id_(id) {}int id() const { return id_; }
private:int id_;
};
/*Book类别
构造函数接受一个格式化字符串
isbn()方法返回该类的isbn号, 典型的ISBN号:"123-456-789-X"
*/
class Book {
public:Book(const std::string& isbn) : isbn_(isbn) {}string isbn() const { return isbn_; }
private:string isbn_;
};void processUser(UserID uid) {cout << "Processing userID: " << uid.id() << endl;
}
void displayBook(Book book) {cout << "DisplayingISBN: " << book.isbn() << endl;
}
我们现在使用我们刚才定义的两个函数看看:
int main() {processUser(12345); // Implicitly converts integer to UserIDdisplayBook("123-456-789-X"); // Implicitly converts C-string to Book
}
在这里就已经发生了隐式对象转换,我们的processUser
函数和displayBook
函数应该分别接受一个UserID类和一个Book类。但是编译器为我们自动得讲int类型转换为了UserID类;将C风格字符串类型转换为了Book类别。
好像还挺不错的,清晰易懂。
产生的问题
一切使用得当,这些转换将按预期工作,但如果由于隐式转换的特性,类型被混合使用或使用不当,问题就会出现:
int main() {displayBook(78910); // Mistakenly passes an integer
}
在上面的代码中,由于 Book
构造函数接受一个 std::string
类型的参数,整数 78910 被隐式地转换为字符串,导致创建了一个 ISBN 为 “78910” 的 Book 对象。这是一个逻辑错误,因为 ISBN 号码并不是简单的整数,它们应该遵循特定的字符串格式。构造函数没有验证输入实际上是否代表一个有效的 ISBN,这可能导致系统数据完整性的潜在错误。
2.使用explicit解决上述问题
class UserID {
public:explicit UserID(int id) : id_(id) {}int id() const { return id_; }
};class Book {
public:explicit Book(const std::string& isbn) : isbn_(isbn) {}std::string isbn() const { return isbn_; }
};
将构造函数标记为 explicit 后,之前的隐式转换将不再被允许:
int main() {processUser(12345); // Error: no viable conversion from 'int' to 'UserID'编译器将为我们报错displayBook("123-456-789-X"); // Error: no viable conversion from 'const char*' to 'Book'编译器将为我们报错// Correct usage requires explicit constructionprocessUser(UserID(12345));displayBook(Book("123-456-789-X"));
}
总结
explicit用于类的构造函数,所以编译器不能听我们隐式得讲任何类型转换为我们的类类型。
通过使用 explicit 关键字,你强制构造函数只被有意识地调用,而不是被编译器来随意使用。从而降低了错误的风险,并使代码的意图更加清晰。这种做法增强了你的应用程序的健壮性和正确性,特别是在类型安全性至关重要的复杂系统中。
我们后续还会讨论它的具体使用。