C++ 是否可以将友元函数声明为静态函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19845478/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to declare a friend function as static?
提问by Jeremy Friesner
Here is some C++ example code that compiles and works fine:
下面是一些编译和工作正常的 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;
}
What I would like to do, however, is declare IncrementValue() as static, so that it can't be seen or called from another compilation unit:
但是,我想要做的是将 IncrementValue() 声明为静态,以便无法从另一个编译单元看到或调用它:
static void IncrementValue(A & a)
{
a.value++;
}
Doing that, however, gives me a compile error:
但是,这样做会给我一个编译错误:
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&)'
... and changing the friend declaration to match doesn't help:
...并且将朋友声明更改为匹配无济于事:
friend static void IncrementValue(A &);
... as it gives this error:
...因为它给出了这个错误:
temp.cpp:8: error: storage class specifiers invalid in friend function declarations
My question is, is there any way in C++ to have a (non-method) friend function that is declared static?
我的问题是,在 C++ 中有什么方法可以有一个声明为静态的(非方法)友元函数?
采纳答案by Praetorian
Quoting N3691 - §11.3/4 [class.friend]
引用 N3691 - §11.3/4 [class.friend]
A function first declared in a friend declaration has external linkage (3.5). Otherwise, the function retains its previous linkage (7.1.1).
首先在友元声明中声明的函数具有外部链接 (3.5)。否则,该函数保留其先前的链接(7.1.1)。
So you need to declare the function as static
prior todeclaring it as a friend
. This can be done by adding the following declarations above the definition of A
.
因此,您需要先声明该函数,static
然后再将其声明为friend
. 这可以通过在A
.
class A; // forward declaration, required for following declaration
static void IncrementValue(A&); // the friend declaration will retain static linkage
回答by Pete Becker
Sure. Read the second line of the error message carefully: the function was declared extern
and laterstatic
. So all you have to do is declare it static before the friend declaration:
当然。仔细阅读错误信息的第二行:函数已声明extern
,稍后static
。所以你所要做的就是在朋友声明之前声明它是静态的:
class A;
static void IncrementValue(A&);
class A {
// class definition, including friend declaration
};
static void IncrementValue(A&) {
// code here, of course
}
回答by Neutrino
While Praetorian's answeris technically correct in that it answers the question you explicitly asked, I believe it is not a useful answer in that what he proposes is both unsound and it also does not fulfill your stated objective of wishing to define a method that can be called in the friend classes' translation unit only.
虽然 Praetorian 的回答在技术上是正确的,因为它回答了您明确提出的问题,但我认为这不是一个有用的答案,因为他提出的建议既不合理,也不符合您既定的目标,即希望定义一种可以仅在朋友类的翻译单元中调用。
There are two problems with his solution. Firstly any other translation unit that includes the header containing the class definition preceeded by the static function declaration will fail to compile due to the error that the statically declared friend function is not defined in the referencing translation module. And secondly, the referencing translation unit can eliminate that compile error by defining the statically declared function itself, and that definition will be able to access all the private data of the class that the function was declared a friend of. This suggests that friend functions should always be left having the public linkage that is their default, as this prevents this potential encapsulation breach due to multiple definitions of a public linkage function being a compile error.
他的解决方案有两个问题。首先,由于静态声明的友元函数未在引用翻译模块中定义的错误,任何其他翻译单元包括包含类定义在静态函数声明之前的头文件将无法编译。其次,引用翻译单元可以通过定义静态声明的函数本身来消除编译错误,并且该定义将能够访问该函数被声明为朋友的类的所有私有数据。这表明友元函数应该始终保留其默认的公共链接,因为这可以防止由于公共链接函数的多个定义是编译错误而导致的潜在封装破坏。
I believe @engf was on the right track in his comment on your question, you need a friend class defined in the same translation unit as the class you wish it to be able to access. E.g.
我相信@engf 在他对您的问题的评论中走在正确的轨道上,您需要在与您希望它能够访问的类相同的翻译单元中定义一个朋友类。例如
// A.h
class A
{
public:
A() : _value(0) {}
private:
int _value;
friend struct A_Accessor;
};
// A.cpp
struct A_Accessor
{
static void IncrementValue(A& a)
{
++a._value;
}
};
TEST(StaticInit, IncrementA)
{
A a;
A_Accessor::IncrementValue(a);
}
This will define IncrementValue in a way that permits it to access A's private data, yet cannot be referenced from outside A's translation module.
这将以允许它访问 A 的私有数据但不能从 A 的翻译模块外部引用的方式定义 IncrementValue。