繁体   English   中英

是否可以将友元函数声明为静态函数?

[英]Is it possible to declare a friend function as static?

下面是一些编译和工作正常的 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;
}

但是,我想做的是将 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++ 中有什么方法可以有一个声明为静态的(非方法)友元函数?

引用 N3691 - §11.3/4 [class.friend]

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

因此,您需要先将该函数声明为static函数,然后再将其声明为friend 这可以通过在A的定义上方添加以下声明来完成。

class A;  // forward declaration, required for following declaration
static void IncrementValue(A&); // the friend declaration will retain static linkage

当然。 仔细阅读错误消息的第二行:函数被声明为extern后来被声明为static 所以你所要做的就是在朋友声明之前声明它是静态的:

class A;
static void IncrementValue(A&);

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

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

虽然 Praetorian 的回答在技​​术上是正确的,因为它回答了您明确提出的问题,但我认为这不是一个有用的答案,因为他提出的建议既不合理,也不符合您既定的目标,即希望定义一种可以仅在朋友类的翻译单元中调用。

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

我相信@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);
}

这将以允许它访问 A 的私有数据但不能从 A 的翻译模块外部引用的方式定义 IncrementValue。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM