C++ 友元函数-声明顺序
我有两个类叫做C++ 友元函数-声明顺序,c++,header-files,friend-function,C++,Header Files,Friend Function,我有两个类叫做Screen和Window\u mgr 屏幕允许窗口管理器通过好友函数声明修改其私有/受保护成员 因此,Window\u-mgr在代码的最后定义了一个名为Window\u-mgr::clear的非成员函数,该函数应该使用它 不幸的是,我犯了一些可笑的错误,我无法解释自己 我错过了什么 屏幕.h #pragma一次 #ifndef屏幕 #定义屏幕 #包括 #包括 班级窗口经理{ 公众: //窗口上每个屏幕的位置ID 使用ScreenIndex=std::vector::size\u
Screen
和Window\u mgr
屏幕
允许窗口管理器
通过好友函数声明修改其私有/受保护成员
因此,Window\u-mgr
在代码的最后定义了一个名为Window\u-mgr::clear
的非成员函数,该函数应该使用它
不幸的是,我犯了一些可笑的错误,我无法解释自己
我错过了什么
屏幕.h
#pragma一次
#ifndef屏幕
#定义屏幕
#包括
#包括
班级窗口经理{
公众:
//窗口上每个屏幕的位置ID
使用ScreenIndex=std::vector::size\u type;
//在给定位置将屏幕重置为所有空白
空白清除(屏幕索引);
私人:
病媒筛选{Screen(24,80,')};
};
类屏幕{
公众:
//朋友
朋友无效窗口管理器::清除(屏幕索引);
//朋友班窗口经理;
//田地
//typedef=>创建别名
//typedef std::string::size_type pos;
//使用类型别名声明类型成员的替代方法
使用pos=std::string::size\u类型;
//建设者
Screen()=default;//需要,因为Screen有另一个构造函数
//游标由其类内初始值设定项初始化为0
屏幕(位置ht,位置wd,字符c):高度(ht),宽度(wd),内容(ht*wd,c){}//获取光标处的字符
Screen&display(std::ostream&os)//函数位于类body=>隐式内联中
{
do_显示(操作系统);
归还*这个;
}
const Screen&display(std::ostream&os)const//函数位于类body=>隐式内联中
{
do_显示(操作系统);
归还*这个;
}
//方法
char get()const{return contents[cursor];}//隐式内联
内联字符get(pos-ht,pos-wd)const;//显式内联
屏幕和移动(位置r、位置c);//稍后可以内联进行
屏幕和设置(字符);
屏幕和设置(pos、pos、char);
私人:
//田地
可变大小访问控制;
pos游标=0;
位置高度=0,宽度=0;
std::字符串内容;
//方法
void do_显示(标准::ostream&os)常量{os您不能在窗口\u mgr
类中声明Screen
对象的向量,因为编译器在代码中的该点不知道Screen
。如果要声明指针向量,您可以通过向前声明Screen
来修复它,但对于实际对象的向量,则需要完整定义必须是可用的
您需要切换窗口管理器
和屏幕
的顺序,并向窗口管理器
类声明友谊:
class Screen {
public:
friend class Window_mgr;
...
};
class Window_mgr {
public:
// location ID for each screen on the window
using ScreenIndex = std::vector<Screen>::size_type;
// reset the Screen at the given position to all blanks
void clear(ScreenIndex);
private:
std::vector<Screen> screens{ Screen(24, 80, ' ') };
};
类屏幕{
公众:
朋友班窗口经理;
...
};
班级窗口经理{
公众:
//窗口上每个屏幕的位置ID
使用ScreenIndex=std::vector::size\u type;
//在给定位置将屏幕重置为所有空白
空白清除(屏幕索引);
私人:
病媒筛选{Screen(24,80,')};
};
为什么编译器知道Window\u-mgr
但不知道Window\u-mgr::ScreenIndex
C++对友谊声明中使用的类名有一个特殊规则:
如果尚未声明友元声明中使用的类的名称,则会当场进行前向声明
这就是编译器“知道”窗口管理器的原因(也就是说,它不知道;你可以相信它)。对于在“befriended”类中声明的成员函数或成员类型,没有这样的规则。这就是为什么编译器不知道关于窗口管理器::ScreenIndex
,我建议不要使用“friend”为此,只需将clear()public member函数添加到类屏幕,并从窗口管理器调用它
// declaration
Screen &clear();
// definition
inline Screen &Screen::clear() {
contents.resize(height * width, ' ');
return *this; // return this object as an lvalue
}
// use
void Window_mgr::clear(ScreenIndex i)
{
// s is a reference to the Screen we want to clear
Screen &s = screens[i];
// reset the contents of that Screen to all blanks
s.clear();
}
在中查看它是否缺少#include
和#include
?很抱歉,忘记复制它的最新版本,即使包含向量,我仍然会收到关于“屏幕:未声明的标识符”的错误消息等等。我在文件顶部添加了一个类屏幕;
用于声明屏幕
,但这并不能完全解决问题。类屏幕;
在顶部可以解决问题,如果你想做向量
,但是对于向量
,必须提供完整的屏幕
。非常感谢你的帮助您的答案-这是我最终找到的解决方案之一。不幸的是,这不适用于friend void Window\u mgr::clear(ScreenIndex)
而不是朋友类窗口管理器;
-这是因为它自己引用的朋友函数声明是窗口管理器的ScreenIndex
-知道如何避免这种交叉引用吗?是的,仍然是相同的错误。无论如何,我认为会有一个简单的解决方案。尽管我仍然不能完全理解nd为什么好友类窗口\u mgr
没有问题,而好友无效窗口\u mgr::clear(窗口\u mgr::屏幕索引)没有问题
。两者都引用了窗口\u mgr
或编译器此时不应知道的其中一个成员。@Hansmusterwhat若要向前声明函数,编译器需要在向前声明窗口\u mgr::clear(窗口\u mgr::ScreenIndex)时定义参数类型编译器不知道什么是Window\u mgr::ScreenIndex,您正在将Window\u mgr的定义推迟到Screen定义之后。那么,为什么编译器知道Window\u mgr
,而不知道Window\u mgr::ScreenIndex
?这是基于它与friend class Window\u mgr;
@HansmusterHatels完美配合的知识e有关此差异的解释,请参见编辑。
// declaration
Screen &clear();
// definition
inline Screen &Screen::clear() {
contents.resize(height * width, ' ');
return *this; // return this object as an lvalue
}
// use
void Window_mgr::clear(ScreenIndex i)
{
// s is a reference to the Screen we want to clear
Screen &s = screens[i];
// reset the contents of that Screen to all blanks
s.clear();
}