在编写新的类函数时,我通常可以安全地将函数定义的第一行(从源文件中)复制到类头中以添加声明,使其成为类的一部分。我通常不使用 C++ 中的结构,但现在我遇到了这样一种情况,即在定义的参数列表中指定结构似乎有一些特殊情况。该结构是同一类的数据成员。
头文件中的函数定义:
int freq_sort(unsigned char* source, struct freq_pair* target);
源文件中该函数定义的第一行:
int TargaImage::freq_sort(unsigned char* source, struct freq_pair* target){
关于声明的编译器错误:
TargaImage.cpp:324:5: error: no declaration matches ‘int TargaImage::freq_sort(unsigned char*, TargaImage::freq_pair*)’
324 | int TargaImage::freq_sort(unsigned char* source, struct freq_pair* target){
| ^~~~~~~~~~
编译器错误提示正确定义:
TargaImage.h:96:13: note: candidate is: ‘int TargaImage::freq_sort(unsigned char*, freq_pair*)’
96 | int freq_sort(unsigned char* source, struct freq_pair* target);
| ^~~~~~~~~
结构数据成员:
struct freq_pair {
unsigned char val;
int count;
};
我看到编译器看到的主要区别是定义中的 struct 参数而不是声明中使用的范围解析运算符。我不明白为什么会这样。这里发生了什么?
我试图在定义、声明或两者中将类范围添加到 struct 参数,以哄骗它工作但无济于事。即使这样做了,我也不明白问题是什么。
在这里找到问题的下一步是什么?
谢谢,
特伦特
编辑 1:
这是原始问题的最小可重现代码,从评论中获得的见解没有任何变化。
class TargaImage
{
public:
//function
int freq_sort(unsigned char* source, struct freq_pair* target);
//data member
struct freq_pair {
unsigned char val;
int count;
};
};
int TargaImage::freq_sort(unsigned char* source, struct freq_pair* target){
return 0;
}
int main(){
TargaImage obj;
return 0;
}
现在我明白了以与类类似的方式来考虑结构。因此,如果我本质上是在我的原始类中定义一个新的“类”(结构),那么包含该类以供使用的规则必须不同于通常的预处理器指令。我认为,由于新的 freq_pair“类”(结构)在原始 TargaImage 类中,因此它的定义在 TargaImage 成员函数的范围内。因此,从参数中删除 struct 关键字。但我得到了错误:
main.cpp:6:42: error: ‘freq_pair’ has not been declared
6 | int freq_sort(unsigned char* source, freq_pair* target);
|
所以我的结论是 freq_pair 超出了 TargaImage 的范围,尽管它是在类中定义的。这个结论正确吗?我应该如何通知 TargaImage::freq_sort(...) 类类型 freq_pair?
我认为将 C 风格的结构添加为数据成员是个好主意,但主要的收获可能是在其他地方定义一个类来保存结构所持有的一对数据成员。
最佳答案
C++是从源代码自上而下编译的。除了在模板中,每次遇到标识符时,都会执行名称查找。这意味着编译器试图在源代码的前一部分中找到标识符的可达声明。
这里使用标识符 freq_pair
第一次在函数参数里面
int freq_sort(unsigned char* source, struct freq_pair* target);
因为没有事先声明,所以编译器还不知道是什么
freq_pair
应该是。通常这会导致错误提示 freq_pair
未声明。然而 struct
关键字基本上告诉编译器:“freq_pair
是一个类类型,如果你没有找到这样的类类型,那么在这里声明它。”因此
freq_pair
将被声明,但问题是它将被声明的确切位置(即在哪个范围内)。它可以在 struct
内声明为嵌套类(class
和 TargaImage
都引入类,在 C++ 中,两者在类型标识方面没有区别) ,作为函数的局部类或全局类。实际上是后者,如[basic.scope.pdecl]/7.2 C++17 标准(草案 N4659)的规定(另见 this question 以了解类似情况):for an elaborated-type-specifier of the form
class-key identifier
如果 [...];否则,除非作为友元声明,否则标识符将在包含该声明的最小命名空间或 block 范围内声明。
详细类型说明符是使用struct
的类型说明符。或其他类键关键字之一,即您所拥有的struct freq_pair
.您的函数声明位于类范围内(既不是命名空间范围也不是 block 范围),因此freq_pair
的声明不能放在那里。包含class TargaImage {...};
的下一个最小范围是全局作用域,它被认为是命名空间作用域。因此这条线int freq_sort(unsigned char* source, struct freq_pair* target);
声明一个全局struct freq_pair
声明中提到的类型就是那个类型。
然后struct freq_pair { unsigned char val; int count; };
定义一个类freq_pair
嵌套在类中TargaImage
.这与您事先声明的全局类不同。
然后我们来定义int TargaImage::freq_sort(unsigned char* source, struct freq_pair* target){ return 0; }
在这里,因为我们定义了一个函数,它是TargaImage
的一部分。 , 名称freq_pair
第一次在TargaImage
内部查找, 我们现在看到定义struct freq_pair {...};
其中声明了freq_pair
嵌套在TargaImage
内,即TargaImage::freq_pair
.struct
如果可以找到与名称匹配的类型,则关键字不会产生任何进一步的影响,因此freq_pair
在这个定义中现在指TargaImage::freq_pair
.
结果,您声明了一个成员函数,该函数采用指向全局::freq_pair
的指针。 ,但试图定义一个成员函数,该函数采用指向嵌套::TargaImage::freq_pair
的指针.编译器提示这些不匹配。
要解决此问题,请删除所有struct
变量声明中的关键字,并且仅将其用于定义或显式前向声明类。如您所见,将其用作详细的类型说明符只会让人头疼。相同的规则适用于其他详细的类型说明符,即那些以class
开头的说明符。/enum
/union
.
但是,这样做会导致错误,因为freq_pair
如上所述,在成员声明中找不到。这很容易通过移动freq_pair
的定义来解决。使用点前:class TargaImage { public: //data member struct freq_pair { unsigned char val; int count; }; //function int freq_sort(unsigned char* source, freq_pair* target); }; int TargaImage::freq_sort(unsigned char* source, freq_pair* target){ return 0; }
如果由于某种原因这不可能,那么您可以使用前向声明来确保第一次查找找到正确的类型(即使此时它不完整):class TargaImage { public: //explicit forward declaration struct freq_pair; //function int freq_sort(unsigned char* source, freq_pair* target); //data member struct freq_pair { unsigned char val; int count; }; }; int TargaImage::freq_sort(unsigned char* source, freq_pair* target){ return 0; }
另请注意freq_pair
是嵌套类,而不是数据成员。
关于c++ - 当其中之一是结构时,C++ 类函数参数语法有什么不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58631258/