这类似于(但不同)这个问题。
这里有一些简单的测试代码来说明我在 Sun CC 中发现的一些奇怪之处:
//---------------main.cpp
#include "wtc.hpp"
int main(int, char**)
{
testy t;
t.lame(99);
return 0;
}
//--------------wtc.hpp
#ifndef WTC_HPP_INCLUDED
#define WTC_HPP_INCLUDED
class testy
{
public:
void lame(int );
};
#endif
//---------------wtc.cpp
#include <iostream>
#include "wtc.hpp"
void testy::lame(const int a)
{
std::cout << "I was passed " << a << "\n";
}
//---------------makefile
#CXX=CC
CXX =g++
#CXXFLAGS= -g
CXXFLAGS= -g3 -Wall -Werror
OBJECTS=$(patsubst %.cpp,%.o,$(wildcard *.cpp))
all : $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $@ $^
.PHONY: clean
clean :
rm *.o
当使用 g++ 编译它时,它会编译、链接并执行您在运行时所期望的操作。 您还可以添加 ++a;在 testy::lame() 中,编译器会抱怨更改只读变量(正如它应该的那样)。
但是,当我使用 CC 编译时,出现以下链接器错误:
CC -g -c -o main.o main.cpp
CC -g -c -o wtc.o wtc.cpp
CC -g -o all main.o wtc.o
Undefined first referenced
symbol in file
void testy::lame(int) main.o
ld: fatal: Symbol referencing errors. No output written to all
make: *** [all] Error 1
用 nm 和 C++filt 检查目标代码,我发现 g++ 版本创建了一个 testy::lame(int) 符号,而 CC 创建 testy::lame(const int) ,因此链接器错误。
我在Stroustrup的书中查找了它,但找不到提到的这种技术(并不意味着它不存在!);那么这真的是一个编译器错误,还是只是一个在除 Solaris 之外的其他地方都有效的 hack?
这看起来像是
CC
中的编译器问题。 C++ 标准说(在 13.1 可重载声明中):
仅在是否存在 const 和/或 volatile 方面不同的参数声明是等效的。也就是说,在确定正在声明、定义或调用哪个函数时,将忽略每个参数类型的 const 和 volatile 类型说明符。
但是有
const
/volatile
修饰符可以参与重载,正如标准随后不久提到的:
以这种方式仅忽略参数类型规范最外层的 const 和 volatile 类型说明符;隐藏在参数类型规范中的 const 和 volatile 类型说明符非常重要,可用于区分重载函数声明。
“const int”参数中的“const”应该被编译器忽略。然而,至少可以说,声明和定义之间的差异是糟糕的风格。
我的理解是这是允许的,因为这对调用者来说没有什么区别。它不是 const 函数,而是参数,并且您正在定义中进行添加。因此,您实际添加的 const 仅影响实现
看到这个问题。
我总是会在声明和定义上匹配
const
。这会减少任何问题,因为签名会匹配。
const
是 void func1(const int)
对函数没有任何影响,因为 int 是按值传递的——创建了 int 的副本,并且该副本仅在函数调用期间存在。无论您是否更改该副本都没有任何影响。
您可能会对
void func2(const char*)
中 const
很重要这一事实感到困惑。但你必须认识到这与void func3(char* const)
不同。前者是指向的字符,不能改变;在后者中,指针是(无关紧要的)“const”
请参阅 Alexandrescu 的 C++ 编码标准 #15。按照他的说法,这应该有效。 const 防止函数的实现者更改输入变量。 IMO 变量应在函数内保持 const 状态。如果您需要一个变量,请声明一个。优化器会帮你去掉它。
int temp = a;
由于这在这里不起作用,我建议我的类在原型和实现中都使用 (const int a) 。我非常喜欢使用适用于所有编译器的技术。
您的代码是正确的;正如 Michael Burr 的回答所示,编译器存在问题。
以下两个函数声明是相同的:
void Print(int number);
void Print(const int number); // Okay. Redeclaration of Print(int).
一般来说,大多数风格指南建议不要在函数声明中使用不必要的 const。因此,在上面的示例中,首选第一个声明。例如,请参阅:https://abseil.io/tips/109
但是,以下两个函数定义是不同的:
void Print(int number) {
std::cout << number << std::endl;
}
void Print(const int number) { // Error: Redefinition of Print(int).
std::cout << number << std::endl;
}
这两个定义都定义了相同的函数声明
Print(int)
,因此第二个定义会由于单一定义规则而导致编译错误。然而,第二个定义(带有 const
的定义)更清晰:它表示参数的值不能在函数内部更改,并防止未来的开发人员意外修改参数的值。在这样一个简单的例子中,这可能并不重要,但一般来说,大多数风格指南都鼓励在函数定义中使用 const
;请参阅上面的 Abseil 库链接。
总体而言,通常推荐的方法是避免在函数声明中使用不必要的
const
,而是在函数定义中使用 const
。示例:
// Header file:
void Print(int number);
// Source file:
void Print(const int number) {
std::cout << number << std::endl;
}
是的,const int 与 int 不同。