上代碼
#include <iostream>
#include <sstream>
using namespace std;
class A
{
public:
A(const string &book = "ab") : s(book) {}
int same_s(const A &a) const
{ return s == a.s; }
private:
string s;
};
int main(int argc ,char **argv)
{
A c("aaa");
string m = "aaa";
cout << c.same_s(m) << endl;
}
究其因
same_s應該接收一個類A的對象參數,但是這裡直接傳了一個字元串對象。過程這樣:編譯器接收一個string的對象,利用構造函數 A(const string &book = "ab") 生成臨時對象(隐性轉換),然後傳遞給same_s,臨時對象失效.
注意: explicit 隻能用于類内部的構造函數的聲明上。
explicit和構造函數一起使用.
explicit constructor指明構造函數隻能顯式使用,目的是為了防止不必要的隐式轉化.
如何防止隐性轉換
構造函數加關鍵字explicit
#include <iostream>
#include <sstream>
using namespace std;
class A
{
public:
explicit A(const string &book = "ab") : s(book) {}
int same_s(const A &a) const
{ return s == a.s; }
private:
string s;
};
int main(int argc ,char **argv)
{
A c("aaa");
string m = "aaa";
cout << c.same_s(m) << endl;
}
結果出錯
解決之道
字元串強制傳遞給構造函數
#include <iostream>
#include <sstream>
using namespace std;
class A
{
public:
explicit A(const string &book = "ab") : s(book) {}
int same_s(const A &a) const
{ return s == a.s; }
private:
string s;
};
int main(int argc ,char **argv)
{
A c("aaa");
string m = "aaa";
cout << c.same_s(A(m)) << endl;
}
同理
對于 A a = string("hello")來說,如果參數為string的構造函數為explicit,則這樣初始化是錯誤的;如果不是explicit,則這樣初始化是正确的(先利用構造函數生成臨時對象,再把臨時對象通過指派操作符複制到新建立的對象上)。
對比實驗
對
#include <iostream>
#include <sstream>
using namespace std;
class A
{
public:
A(const string a) : s(a) {}
private:
string s;
};
int main(int argc ,char **argv)
{
A a = string("hello");
}
錯
#include <iostream>
#include <sstream>
using namespace std;
class A
{
public:
explicit A(const string a) : s(a) {}
private:
string s;
};
int main(int argc ,char **argv)
{
A a = string("hello");
}