[英]implicit conversions from and to class types
我正在研究用C ++轉換構造函數和轉換運算符。 到目前為止我學到的是,任何只帶一個參數(以及任意數量的可選默認參數)的非顯式構造函數表示對THAT類類型的隱式類類型轉換,例如,如果類定義了一個構造函數, int
類型的一個參數我可以在需要該類類型的對象的地方使用int
:
(假設class_type有一個重載的+ =運算符)
class_type a;
a+=5;
在這種情況下,5被隱式轉換(通過轉換構造函數)到class_type
並調用重載的運算符。
現在,(至少對我來說)棘手的部分:我知道我可以將轉換運算符定義為成員函數:
operator int() {....};
將class_type
的對象轉換為原始int
類型,我可以使用如下轉換:
class_type a;
a+5;
在這種情況下,我已經讀過通過其轉換運算符將對象轉換為int,然后調用內置和運算符。 但是如果我定義了一個重載的+運算符來將兩個class_type對象作為其參數呢? 就像是
class_type operator+(const class_type&,const class_type &c);
編譯器如何知道通過函數匹配調用哪一個? 轉換為int
只會在只定義內置運算符時隱式發生嗎?
謝謝!
編輯:
實際上,我已經嘗試編寫一些代碼來有效地嘗試它,結果發現我的編譯器(g ++)不會發出任何模糊的調用錯誤!
這是類頭(以及非memeber操作符+函數聲明):
#include <iostream>
class wrapper {
friend std::ostream &operator<<(std::ostream&,const wrapper&);
public:
wrapper()=default;
wrapper(int);
int get();
operator int() const;
wrapper operator+(int);
private:
int a=10;
};
std::ostream &operator<<(std::ostream&,const wrapper&);
這是主要代碼:
#include "wrapper.h"
int main()
{
using namespace std;
wrapper w1;
wrapper w2(5);
cout<<w1<<" "<<w2<<endl;
w1+1;
}
現在,我已經定義了從int
到wrapper
的轉換構造函數以及從類類型到int
的轉換運算符(我還重載了<< output運算符以便打印一些結果),但是當編譯器計算表達式w1+1
似乎很好。 怎么可能?
例如,如果您有包含轉換構造函數和轉換運算符的以下類聲明
struct A
{
A( int x ) : x( x ) {}
operator int() const { return x; }
int x;
};
const A operator +( const A &a1, const A &a2 )
{
return A( a1.x + a2.x );
}
聲明
a1 + a2;
其中a1和a2被聲明為例如
A a1( 10 );
A a2( 20 );
因為不需要調用轉換函數,所以格式正確。 兩個操作數都匹配operator +的參數聲明。
但是,如果你要寫的話
a1 + 20;
當編譯器發出錯誤時,因為存在歧義。 編譯器可以應用轉換構造函數A( int )
將第二個操作數轉換為類型A
並調用為類型A
對象定義的運算符。 或者它可以應用轉換運算符operator int
將第一個操作數轉換為int
類型,並為int
類型的對象調用內置operator +
。
為了避免這種歧義,您可以使用函數說明符explicit
來聲明構造函數或運算符(或兩者)。
例如
explicit A( int x ) : x( x ) {}
要么
explicit operator int() const { return x; }
在這種情況下,只存在一個隱式轉換,並且沒有任何矛盾。
我想附加上面的描述,有時一些轉換運算符可以隱式調用,即使它們是使用函數說明符explicit
。
例如根據C ++標准(6.4選擇語句)
- ...作為表達式的條件的值是表達式的值,對於除switch之外的語句,上下文轉換為bool;
和(5.16條件運算符)
1條件表達式從右到左分組。 第一個表達式在上下文中轉換為bool(第4條)。
因此,例如,如果上面的類具有使用函數說明符explicit
聲明的以下轉換運算符
explicit operator bool() const { return x != 0; }
然而,它將被隱含地稱為例如以下聲明中
A a( 10 );
std::cout << ( a ? "true" : "false" ) << std::endl;
這里a將在條件運算符中轉換為bool類型的對象。
編輯:你更新了這個表達式后的問題
w1+1;
與操作員完全匹配
wrapper operator+(int);
無需轉換。 所以代碼編譯成功。
您可以輕松地嘗試查看編譯器的功能:
#include <iostream>
struct ABC {
int v;
ABC(int x) : v(x) { }
operator int() const { return v; }
void operator +=(ABC const &that) {
v += that.v;
}
};
ABC operator+(ABC const &lhs, ABC const &rhs) {
return { lhs.v + rhs.v };
}
int main() {
ABC a(5);
std::cout << a + 1 << '\n';
a += 10;
std::cout << a << '\n';
}
如果我定義了一個重載的+運算符來取兩個class_type對象作為它的參數怎么辦?
GCC
錯誤:'operator +'的模糊重載(操作數類型是'ABC'和'int')
編譯器看到兩個候選者: operator+(int, int) <built-in>
和ABC operator+(const ABC&, const ABC&)
。 這意味着它不僅可以隱式地將a + 5
的5
轉換為a
而且將a
為int
。 發布這些轉換后, operator+
函數都會成為潛在匹配。
編譯器如何知道通過函數匹配調用哪一個?
因此不知道錯誤。
轉換為
int
只會在只定義內置運算符時隱式發生嗎?
是的,否則它不會自動將class_type
轉換為int
。 但是, int
到class_type
會隱式發生,除非你使class_type
的構造函數explicit
:
explicit ABC(int x) : v(x) { }
如果您可以訪問C ++ 11,那么您還可以顯式轉換函數:
explicit operator int() const { return v; }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.