C++ 为什么结构需要友元函数?
我正在尝试建立一个我从互联网下载的源代码。当我试图编译它时,我得到了错误消息C++ 为什么结构需要友元函数?,c++,C++,我正在尝试建立一个我从互联网下载的源代码。当我试图编译它时,我得到了错误消息 friend declaration specifying a default argument must be the only declaration 以下是违规代码: typedef int Var; struct Lit { int x; // Use this as a constructor: friend Lit mkLit(Var var, bool sign = fa
friend declaration specifying a default argument must be the only declaration
以下是违规代码:
typedef int Var;
struct Lit {
int x;
// Use this as a constructor:
friend Lit mkLit(Var var, bool sign = false);
bool operator == (Lit p) const { return x == p.x; }
bool operator != (Lit p) const { return x != p.x; }
bool operator < (Lit p) const { return x < p.x; }
inline Lit mkLit(Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }
typedef int-Var;
结构照明{
int x;
//将其用作构造函数:
friend Lit mkLit(Var-Var,bool符号=false);
布尔运算符==(Lit p)常量{return x==p.x;}
布尔运算符!=(亮p)常量{return x!=p.x;}
布尔运算符<(Lit p)const{return x
我发现了几个问题可以解决这个问题,但问题相当深奥,我不太理解其中的解释。这表明我可以通过将mkLit
的内联定义移到结构之前,从友元函数声明中删除默认参数,并将其移到内联de来解决问题定义,对吗
但更基本的是,我不明白为什么一个结构需要一个friend函数,因为它的成员无论如何都是公共的。对于依赖于参数的查找,已被接受的答案给出了一个答案(我的无知使我无法理解),但我看不出它是否适用于这种情况
删除友元函数声明并将默认参数移动到内联函数定义有什么缺点吗?如果有,你能给我一个简单的例子吗
但更基本的是,我不明白为什么一个结构需要一个朋友
函数,因为其成员无论如何都是公共的
<>这是一个误解。C++中没有结构和类,但是C++只有一个类,它们可以用关键字<代码>结构> <代码>或<代码>类<代码>来声明。唯一的区别是默认访问(即,除了它们的成员的顺序,如果您的地址有问题),它们是相同的:
与类
相同:
class foo : bar {
int y;
public:
int x;
};
使用class
或struct
声明一个类纯粹是一个惯例问题。因此,您的问题转化为“为什么一个类需要一个友元函数?”答案是:允许友元访问私有字段
这是关于内联定义友元函数,而不是仅仅声明它,即
struct foo {
friend void foofriend() { /*put implementation here*/ }
};
vs
这确实与ADL有关(我也无法解释),并且与朋友的好处有点正交。正如许多人之前提到的那样,
struct
与类
相同,只是其成员默认为公共
。它可以有私人成员
我在这里猜测,但我认为让它成为朋友工厂函数背后的想法是,它库的设计者保留初始化将来添加的任何私有成员的权利
回答您的问题:
- 将默认参数移动到内联函数似乎有效
- 将
移动到mkLit
之前是一个问题,因为它返回struct
,并且Lit
尚未定义(因为它现在显示在Lit
下面)mkLit
- 删除
中的struct
声明将起作用,因为friend
目前没有私有成员。如果您在原始库的较新版本中进行合并,则会添加私有成员(或通过将文本struct
更改为struct
,默认情况下使成员私有),然后它将停止工作class
(注意:我将您的代码粘贴到中,并使用不同的编译器尝试了各种排列)我花了一段时间才得到它,但最终我发现了 因此,我忽略了mis的主要标题(该标题已被IMHO充分使用),而专注于 指定默认参数的友元声明必须是唯一的声明 这引起了我的注意 因此,我不会重复关于
朋友
和访问公共成员的内容,因为我认为这个错误处理的是另一个问题
首先,我尝试了coliru上的OP示例(有一个小补丁和一个main()
测试):
啊,是的,跑得很好
然后,这次我在wandbox上使用了ClangHead8.0.0
:
开始
prog.cc:7:16:错误:指定默认参数的友元声明必须是定义
friend Lit mkLit(Var-Var,bool符号=false);
^
prog.cc:12:14:错误:指定默认参数的友元声明必须是唯一的声明
内联Lit mkLit(Var-Var,bool-sign){Lit p;p.x=Var+Var+(int)符号;返回p;}
^
进度cc:7:16:注:此处为先前声明
friend Lit mkLit(Var-Var,bool符号=false);
^
产生2个错误。
1.
完成
我们到了
所以,我试着去理解clang
抱怨什么
最后,我发现clang
查找Lit::mkLit()
,这与后面定义的Lit mkLit()
不匹配
这可以通过在struct Lit
之前插入的mkLit()的原型来解决:
typedef int Var;
Lit mkLit(Var var, bool sign = false);
struct Lit {
int x;
// Use this as a constructor:
friend Lit mkLit(Var var, bool sign);
bool operator == (Lit p) const { return x == p.x; }
bool operator != (Lit p) const { return x != p.x; }
bool operator < (Lit p) const { return x < p.x; }
};
输出:
开始
lit2.x:246
0
完成
问题解决了
我必须承认,我不确定g++
是否接受原始版本(虽然不应该),或者clang
是否拒绝原始版本(虽然不应该)。我的胃痛倾向于前者(即clang
是正确的)
在再次思考了在g++
中发生的事情之后,我得出结论,它可以做到以下几点:
接受好友Lit::mkLit()
(从未使用过)
Lit mkLit()
struct foo {
friend void foofriend();
};
void foofriend() { /*put implementation here*/ }
#include <iostream>
typedef int Var;
struct Lit {
int x;
// Use this as a constructor:
friend Lit mkLit(Var var, bool sign = false);
bool operator == (Lit p) const { return x == p.x; }
bool operator != (Lit p) const { return x != p.x; }
bool operator < (Lit p) const { return x < p.x; }
};
inline Lit mkLit(Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }
int main()
{
Lit lit2 = mkLit(123, false);
std::cout << "lit2.x: " << lit2.x << '\n';
return 0;
}
typedef int Var;
Lit mkLit(Var var, bool sign = false);
struct Lit {
int x;
// Use this as a constructor:
friend Lit mkLit(Var var, bool sign);
bool operator == (Lit p) const { return x == p.x; }
bool operator != (Lit p) const { return x != p.x; }
bool operator < (Lit p) const { return x < p.x; }
};
#include <iostream>
typedef int Var;
struct Lit;
Lit mkLit(Var var, bool sign = false);
struct Lit {
int x;
// Use this as a constructor:
friend Lit mkLit(Var var, bool sign);
bool operator == (Lit p) const { return x == p.x; }
bool operator != (Lit p) const { return x != p.x; }
bool operator < (Lit p) const { return x < p.x; }
};
inline Lit mkLit(Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }
int main()
{
Lit lit2 = mkLit(123, false);
std::cout << "lit2.x: " << lit2.x << '\n';
return 0;
}
#include <iostream>
typedef int Var;
class Lit {
int x;
// Use this as a constructor:
friend Lit mkLit(Var var, bool sign = false);
bool operator == (Lit p) const { return x == p.x; }
bool operator != (Lit p) const { return x != p.x; }
bool operator < (Lit p) const { return x < p.x; }
};
inline Lit mkLit(Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }
int main()
{
Lit lit2 = mkLit(123, false);
std::cout << "lit2.x: " << lit2.x << '\n';
return 0;
}