函数重定义:const参数 1在全球范围内,这给出了error: redefinition of 'f' 2定义两个副本构造函数一个带有const,另一个没有问题

问题描述

1。在全球范围内,这给出了error: redeFinition of 'f'

#include <iostream> 
using namespace std; 
  
void f(int x) { cout << "f" << endl; }
void f(const int x) { cout << "f (const)" << endl; } // error: redeFinition of 'f'
int main() { } 

2。定义两个副本构造函数一个带有const,另一个没有)

#include <iostream> 
using namespace std; 
  
class Foo { 
public: 
    Foo(const Foo&) { cout << "copy (const)" << endl; }
    Foo(Foo&) { cout << "copy" << endl; }
}; 

int main() { } 

问题

  1. 为什么#1是重新定义错误,但#2不是?
  2. 对于第二个示例,是否存在用例来定义两个副本构造函数一个带有const,另一个没有)?

解决方法

两者之间有根本的区别。

一个是intconst int之间的重载。这是一个值类型。调用者在语义上没有区别,const的作用仅影响函数的主体。

void f(int);

int a = 1;
const int b = 2;

f(a); // must copy the int value into the argument
f(b); // same thing.

另一个是const与可变的 reference 。对于呼叫者来说有所不同。

void f(int&);
void f(const int&);

int a = 1;
const int b = 2;

f(a); // could call f(int&) or f(int const&),but the mutable is a more closely match
f(b); // can only call f(int const&);

自引用传递以来,常量对于函数的调用者至关重要。试图通过引用使const对象变异的函数必须无效,并且默认情况下,应将非const对象传递给non const重载。

仅具有值,根本没有关系。这是一个新对象。不管限定词是什么,对于调用者来说都没有意义,因此它不应该在乎,因为它只会影响实现。

您甚至可以只在需要时在定义中添加const,因为它声明了相同的功能:

void f(int);

int main() {
    f(1);
}

void f(const int a) {
    std::cout << "hello " << a << std::endl;
}

Live example


关于您的第二个问题,我想说的是,由于添加了右值引用,因此几乎不需要复制构造函数通过可变引用来获取。

例如,std::auto_ptr曾经有一个构造函数,该构造函数使用可变的引用来转让所有权,但它会产生各种问题。但是它已被std::unique_ptr完全取代,后者使用右值引用来转移所有权。

右值引用可确保您不关心复制对象的完整性,并且可以从中窃取资源。

,

在检查两个函数是否相同时,仅忽略参数的顶级const

“顶级”常量性是什么意思?正如std::is_const_v所报告的,这意味着某些东西实际上是const。

例如int *const是顶级const(因为指针本身是const),而const int *不是(因为指针本身不是const,甚至尽管它指向的是const)。

某些事物可以在多个层次上保持不变,例如const int *const

const int也是顶级常量,因为这里只有一个“级别”。

如果您有一颗以上的星星(例如int ***),则只有将const放在最右边的星星之后,该类型才是顶级const。


因此,const int在顶层是const,这意味着const intint仅在顶层constness上有所不同。

但是(类似于const int *const Foo&不是常量。这是对const Foo的非常量引用。 (引用绝不能是const 1 ,例如Foo &const不会编译。)

因此Foo &const Foo &之间的区别不在顶层,从而使Foo(Foo &)Foo(const Foo &)成为不同的构造函数。


1 有人认为,所有引用实际上都是const,因为在创建引用后您无法使其指向另一个对象。但是该语言表示它们不是const,并且std::is_const_v为它们返回false。

,
  1. #1是重新定义错误,因为即使您修改了本地x,它也会通过值传递,因此在返回调用之后,值将保持不变。