我正在研究g ++,在这里我试图通过向参数添加const
来重载函数。它工作正常,当它运行时,它调用没有const
在没有const
void print(const std::string& str){std::cout << "const" << str << std::endl;}
void print(std::string& str){std::cout << str << std::endl;}
int main()
{
std::string temp = "hello";
print(temp);
return 0;
}
答案 0 :(得分:2)
引用绑定是一个标识类别§13.3.3.1.4)但由于后者更符合cv,对于§13.3.3.2,非const是首选(来自的示例代码)标):
int f(const int &);
int f(int &);
int i;
int j = f(i); // calls f(int &)
答案 1 :(得分:1)
这是标准行为。任何其他行为都会导致疯狂行为。特别是,非const函数根本不可调用。
答案 2 :(得分:1)
const是方法签名的一部分。覆盖仅适用于具有相同签名的方法。 当您使用基类的const方法调用子类的const方法时,这种行为是为了避免相反的情况。
答案 3 :(得分:1)
原因是[over.ics.rank] / 3中的这一部分明确涵盖了这一部分:
标准转换序列
S1
是一个比转换序列更好的转换序列 标准转换序列S2
如果[...] -S1
和S2
是参考 绑定(8.5.3),以及引用引用的类型 相同的类型,除了顶级cv限定符,以及其类型 由S2
引用初始化的引用比cv更合格 由S1
初始化的引用引用的类型。
S1
对应第二个重载,S2
对应第一个重载。
没有
的情况下调用该函数的原因是什么const
您总是尝试选择最专业的东西。就像在函数模板的部分排序中那样,在重载解析中就是这种情况。第二个重载比第一个重载更专业,因为第一个重载可以使用参数调用,第二个不能被调用 - 这是此规则背后的基本推理。
答案 4 :(得分:1)
通过匹配参数的类型(包括限定符)来重载。在您的情况下,temp
的类型std::string
不是const std::string
。你只用一个文字常量初始化它,它本身不是常数。
请考虑以下事项:
std::string temp( "hello" ) ;
print(temp); // hello
print( std::string("hello") ) ; // consthello
print( "hello" ) ; // consthello
print( static_cast<const std::string>(temp) ) ; // consthello
const std::string temp2( "hello" ) ;
print(temp2); // consthello
如果要删除非const版本,则所有三个都将调用剩余的const重载。在此示例中,实际上只有const版本是必需的(并且是首选的),因为两个版本都不修改字符串对象。
如果另一方面你删除了非const版本,除了上面的第一个例子之外,没有任何功能匹配,并且构建将失败。也就是说非const对象可以安全地作为const参数传递,但是const对象不能作为非const参数传递,因为该函数不是&#34;有希望&#34;不要修改对象。您可以通过const_cast
将const强制转换为非const参数,如下所示:
const std::string temp2("hello") ;
print( const_cast<std::string&>(temp2) ) ; // hello
但是如果在这种情况下print()
试图修改对象,结果是 undefined ,那么请认为这种做法不安全。
使参数const表示意图,允许编译器在代码尝试修改对象或通过非const参数将其传递给其他函数时发出诊断。它还可能为编译器提供优化可能性。
答案 5 :(得分:0)
因为调用std::string const&
的函数需要两次隐式转换:一次转换为std::string const
,一次转换为std::string const&
;调用函数std::string&
只需要一次隐式转换(到std::string&
),因此首选。{/ p>