- C++?持內置類型隱式類型轉換為類類型對象,需要有相關內置類型為參數的構造函數。
- ?構造函數前?加explicit就不再?持隱式類型轉換。
- ?類類型的對象之間也可以隱式轉換,需要相應的構造函數?持。
?內置類型隱式類型轉換為類類型對象
在 C++ 中,如果一個類有一個以某種內置類型為參數的構造函數,那么就可以將該內置類型的值隱式轉換為這個類的對象。這種隱式轉換在某些情況下可以讓代碼更加簡潔,但也可能會導致一些意外的行為。
#include <iostream>
class MyClass {
public:// 以 int 為參數的構造函數MyClass(int value) : data(value) {std::cout << "Constructor called with value: " << value << std::endl;}void printData() const {std::cout << "Data: " << data << std::endl;}
private:int data;
};void func(const MyClass& obj) {obj.printData();
}int main() {// 隱式類型轉換:將 int 類型的 10 轉換為 MyClass 類型的對象func(10);return 0;
}
代碼解釋
MyClass
?類有一個以?int
?為參數的構造函數,這使得?int
?類型的值可以隱式轉換為?MyClass
?類型的對象。- 在?
main
?函數中,調用?func(10)
?時,10
?會被隱式轉換為?MyClass
?類型的對象,然后傳遞給?func
?函數。
2. 使用?explicit
?關鍵字禁止隱式類型轉換
在構造函數前面加上?explicit
?關鍵字后,該構造函數就不能用于隱式類型轉換,只能用于顯式的對象構造。這樣可以避免一些潛在的錯誤。
#include <iostream>
class MyClass {
public:// 以 int 為參數的構造函數,使用 explicit 關鍵字explicit MyClass(int value) : data(value) {std::cout << "Constructor called with value: " << value << std::endl;}void printData() const {std::cout << "Data: " << data << std::endl;}
private:int data;
};void func(const MyClass& obj) {obj.printData();
}int main() {// 顯式類型轉換func(MyClass(10));// 以下代碼會編譯錯誤,因為禁止了隱式類型轉換// func(10);return 0;
}
代碼解釋
MyClass
?類的構造函數前面加上了?explicit
?關鍵字,這意味著不能再進行隱式類型轉換。- 在?
main
?函數中,調用?func(MyClass(10))
?時,使用了顯式的對象構造,這樣是合法的。而如果直接使用?func(10)
,則會導致編譯錯誤
3. 類類型的對象之間的隱式轉換
類類型的對象之間也可以進行隱式轉換,前提是有相應的構造函數支持。
#include <iostream>
class Base {
public:Base(int value) : data(value) {std::cout << "Base constructor called with value: " << value << std::endl;}void printData() const {std::cout << "Base Data: " << data << std::endl;}
private:int data;
};class Derived {
public:// 以 Base 類型為參數的構造函數Derived(const Base& base) : baseObj(base) {std::cout << "Derived constructor called" << std::endl;}void printBaseData() const {baseObj.printData();}
private:Base baseObj;
};void func(const Derived& obj) {obj.printBaseData();
}int main() {Base base(10);// 隱式類型轉換:將 Base 類型的對象轉換為 Derived 類型的對象func(base);return 0;
}
代碼解釋
Derived
?類有一個以?Base
?類型為參數的構造函數,這使得?Base
?類型的對象可以隱式轉換為?Derived
?類型的對象。- 在?
main
?函數中,創建了一個?Base
?類型的對象?base
,然后調用?func(base)
?時,base
?會被隱式轉換為?Derived
?類型的對象,然后傳遞給?func
?函數。
示例代碼
#include<iostream>
using namespace std;
class A
{
public:// 構造函數explicit就不再?持隱式類型轉換 // explicit A(int a1)A(int a1):_a1(a1){}//explicit A(int a1, int a2)A(int a1, int a2):_a1(a1), _a2(a2){}void Print(){cout << _a1 << " " << _a2 << endl;}
int Get() const{return _a1 + _a2;}
private:int _a1 = 1;int _a2 = 2;
};
class B
{
public:B(const A& a):_b(a.Get()){}
private:int _b = 0;
};
int main()
{// 1構造?個A的臨時對象,再?這個臨時對象拷?構造aa3 // 編譯器遇到連續構造+拷?構造->優化為直接構造 A aa1 = 1;aa1.Print();const A& aa2 = 1;// C++11之后才?持多參數轉化 A aa3 = { 2,2 };// aa3隱式類型轉換為b對象 // 原理跟上?類似 B b = aa3;const B& rb = aa3;return 0;
}
?
注意:若想打印B類,就要在print后面加const
代碼整體功能概述
這段代碼定義了兩個類?A
?和?B
,其中類?A
?有兩個構造函數,分別接收一個?int
?類型參數和兩個?int
?類型參數;類?B
?有一個以?const A&
?為參數的構造函數。在?main
?函數中,通過不同的方式展示了隱式類型轉換的使用。
具體隱式類型轉換分析
1.?A aa1 = 1;
隱式類型轉換過程:類?A
?有一個以?int
?為參數的構造函數?A(int a1)
,當執行?A aa1 = 1;
?時,編譯器會利用這個構造函數將?int
?類型的?1
?隱式轉換為?A
?類型的臨時對象,然后使用這個臨時對象進行拷貝構造?aa1
。不過,現代編譯器通常會對這種連續的構造和拷貝構造操作進行優化,直接將其轉換為直接構造,也就是直接調用?A(int a1)
?來構造?aa1
?對象。
- 執行結果:調用?
A(int a1)
?構造函數,將?_a1
?初始化為?1
,_a2
?使用默認值?2
。隨后調用?aa1.Print()
?會輸出?1 2
。
2.?const A& aa2 = 1;
隱式類型轉換過程:同樣基于類?A
?的?A(int a1)
?構造函數,將?int
?類型的?1
?隱式轉換為?A
?類型的臨時對象。由于?aa2
?是一個常量引用,它可以綁定到這個臨時對象上,延長臨時對象的生命周期,使其在?aa2
?的作用域內保持有效。
- 執行結果:創建一個?
A
?類型的臨時對象,_a1
?為?1
,_a2
?為?2
,aa2
?引用這個臨時對象。
3.?A aa3 = { 2, 2 };
- 隱式類型轉換過程:在 C++11 及以后的標準中,支持多參數的列表初始化進行隱式類型轉換。類?
A
?有一個接收兩個?int
?類型參數的構造函數?A(int a1, int a2)
,因此可以使用?{ 2, 2 }
?這樣的初始化列表來隱式調用該構造函數,將其轉換為?A
?類型的對象。同樣,編譯器會進行優化,直接構造?aa3
?對象。 - 執行結果:調用?
A(int a1, int a2)
?構造函數,將?_a1
?和?_a2
?都初始化為?2
。
4.?B b = aa3
- 隱式類型轉換過程:類?
B
?有一個以?const A&
?為參數的構造函數?B(const A& a)
。當執行?B b = aa3;
?時,aa3
?是?A
?類型的對象,編譯器會使用這個構造函數將?A
?類型的?aa3
?隱式轉換為?B
?類型的對象。同樣,編譯器會優化為直接構造?b
?對象。 - 執行結果:調用?
B(const A& a)
?構造函數,通過?aa3.Get()
?獲取?_a1 + _a2
?的值(這里是?2 + 2 = 4
),并將其賦值給?_b
。
5.?const B& rb = aa3;
- 隱式類型轉換過程:基于類?
B
?的?B(const A& a)
?構造函數,將?A
?類型的?aa3
?隱式轉換為?B
?類型的臨時對象。由于?rb
?是一個常量引用,它可以綁定到這個臨時對象上,延長臨時對象的生命周期。 - 執行結果:創建一個?
B
?類型的臨時對象,_b
?的值為?4
,rb
?引用這個臨時對象。
總結
上述代碼中通過不同的方式展示了隱式類型轉換的應用,包括將內置類型轉換為類類型對象,以及類類型對象之間的轉換。需要注意的是,如果在構造函數前加上?
explicit
?關鍵字,這些隱式類型轉換將被禁止,只能進行顯式的對象構造。