Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
可以将友元函数声明为静态函数吗? 这里是一些编译和运行良好的C++示例代码: class A { public: A() {/* empty */} private: friend void IncrementValue(A &); int value; }; void IncrementValue(A & a) { a.value++; } int main(int, char **) { A a; IncrementValue(a); return 0; }_C++_Static_Friend - Fatal编程技术网

可以将友元函数声明为静态函数吗? 这里是一些编译和运行良好的C++示例代码: class A { public: A() {/* empty */} private: friend void IncrementValue(A &); int value; }; void IncrementValue(A & a) { a.value++; } int main(int, char **) { A a; IncrementValue(a); return 0; }

可以将友元函数声明为静态函数吗? 这里是一些编译和运行良好的C++示例代码: class A { public: A() {/* empty */} private: friend void IncrementValue(A &); int value; }; void IncrementValue(A & a) { a.value++; } int main(int, char **) { A a; IncrementValue(a); return 0; },c++,static,friend,C++,Static,Friend,但是,我想做的是将IncrementValue()声明为静态,这样就不能从另一个编译单元看到或调用它: static void IncrementValue(A & a) { a.value++; } 但是,这样做会导致编译错误: temp.cpp: In function ‘void IncrementValue(A&)’: temp.cpp:12: error: ‘void IncrementValue(A&)’ was declared ‘extern’

但是,我想做的是将IncrementValue()声明为静态,这样就不能从另一个编译单元看到或调用它:

static void IncrementValue(A & a)
{
    a.value++;
}
但是,这样做会导致编译错误:

temp.cpp: In function ‘void IncrementValue(A&)’:
temp.cpp:12: error: ‘void IncrementValue(A&)’ was declared ‘extern’ and later ‘static’
temp.cpp:8: error: previous declaration of ‘void IncrementValue(A&)’
。。。将好友声明更改为匹配也无济于事:

friend static void IncrementValue(A &);
。。。因为它给出了这个错误:

temp.cpp:8: error: storage class specifiers invalid in friend function declarations

我的问题是,C++中有没有一种方法可以声明静态的(非方法)朋友函数?< /p> 当然。仔细阅读错误消息的第二行:函数声明为
extern
,之后声明为
static
。因此,您所要做的就是在朋友声明之前将其声明为静态:

class A;
static void IncrementValue(A&);

class A {
    // class definition, including friend declaration
};

static void IncrementValue(A&) {
    // code here, of course
}

引用N3691-§11.3/4[类朋友]

首先在友元声明中声明的函数具有外部链接(3.5)。否则,该功能将保留其先前的链接(7.1.1)

因此,您需要先将函数声明为
静态
,然后再将其声明为
朋友
。这可以通过在
A
的定义上方添加以下声明来实现

class A;  // forward declaration, required for following declaration
static void IncrementValue(A&); // the friend declaration will retain static linkage
虽然Praetorian’s在技术上是正确的,因为它回答了您明确提出的问题,但我认为这不是一个有用的答案,因为他提出的建议既不合理,也没有实现您希望定义一种只能在朋友类的翻译单元中调用的方法的既定目标

他的解决方案有两个问题。首先,由于引用转换模块中未定义静态声明的友元函数,因此包含包含静态函数声明之前的类定义的头的任何其他转换单元将无法编译。其次,引用转换单元可以通过定义静态声明的函数本身来消除编译错误,并且该定义将能够访问该函数声明为其朋友的类的所有私有数据。这表明朋友函数应该始终保留其默认的公共链接,因为这可以防止由于公共链接函数的多个定义是编译错误而导致的潜在封装破坏

我相信@engf对您的问题的评论是正确的,您需要在您希望它能够访问的类所在的翻译单元中定义一个friend类。例如

//A.h
甲级
{
公众:
A():_值(0){}
私人:
int_值;
友元结构存取器;
};
//A.cpp
结构A_访问器
{
静态无效增量值(A&A)
{
++a、 _值;
}
};
测试(StaticInit,IncrementA)
{
A A;
A_访问器::递增值(A);
}

这将定义IncrementValue,使其能够访问a的私有数据,但不能从a的翻译模块外部引用。

“因此无法从其他编译单元看到或调用它”。你为什么需要这个?(我真的很感兴趣。)这会很奇怪,因为friend函数是类API的一部分,所以实际上你是说你希望类在不同的源文件中有不同的API,这取决于静态函数在每个源文件中的实现方式。请注意,您之所以绕过私有/受保护机制,是因为您已经启用了任何编译单元来提供IncrementValue的静态版本,现在它可以做任何它想做的事情。@Jeremy Friesner:为了真正安全地工作,您需要一个类作为朋友,这是在你的源文件中定义的,因此它只对你可见。如果在多个翻译单元中定义了任何具有内部链接好友的类(因为对于好友声明),那么它将违反ODR,因此好友的内部链接不会改变任何东西。我认为这是非常不明智的。有关详细信息,请参阅我的答案。