c++ - cpp primer 5th 练习7.32(关于友元函数的问题)

浏览:57日期:2023-05-15

问题描述

#include <string>#include<iostream>#include<vector>//test 7.32class Screen;class Window_mgr{public: using ScreenIndex = std::vector<Screen>::size_type; inline void clear(ScreenIndex);private: std::vector<Screen> screens;};class Screen{ friend class Window_mgr; //friend void Window_mgr::clear(ScreenIndex);public: using pos = std::string::size_type; Screen() = default; Screen(pos ht, pos wd) :height(ht), width(wd), contents(ht*wd, ’ ’){} Screen(pos ht, pos wd,char c) :height(ht), width(wd), contents(ht*wd, c){}; char get()const { return contents[cursor]; } char get(pos r, pos c)const { return contents[r*width + c]; } inline Screen& move(pos r, pos c); inline Screen& set(char c); inline Screen& set(pos r, pos c, char ch); const Screen& display(std::ostream &os)const {do_display(os);return *this; } Screen& display(std::ostream &os){do_display(os);return *this; }private: void do_display(std::ostream &os)const {os << contents; }private: pos cursor = 0; pos height = 0, width = 0; std::string contents;};inline void Window_mgr::clear(ScreenIndex i){ if (i >= screens.size()) return; Screen &s = screens[i]; s.contents = std::string(s.height*s.width, ’ ’);}inline Screen& Screen::move(pos r, pos c){ cursor = r*width + c; return *this;}inline Screen& Screen::set(char c){ contents[cursor] = c; return *this;}inline Screen& Screen::set(pos r,pos c,char ch){ contents[r*width + c] = ch; return *this;}

在这段代码中,只有

friend class Window_mgr;

这个类友元,这句:s.contents = std::string(s.height*s.width, ’ ’);才不会有红线标出。

如果将下面这个成员函数友元,不友元类,inline函数内的上面这句则会有红线,显示

friend void Window_mgr::clear(ScreenIndex);

c++ - cpp primer 5th 练习7.32(关于友元函数的问题)

请问这是为什么呢?我是找github上的答案敲的,把他的拷到编译器里面也会出现这个错误。

问题解答

回答1:

其实是因为类相互引用产生的错误。。单独声明Window_mgr是Screen的友员是没有问题的,但是你要是用成员函数就会查找类的定义,而你的Window_mgr里面又含有Screen的成员,这样编译器就懵逼了,我觉得也有可能是实现的问题,虽然我用的gcc也是这样。。

发现下面的代码完全不会编译通过

class Single;class AsFriend{public: AsFriend():__a_single() {} int getSingleValue();private: Single __a_single;};class Single{public: Single():some_member(42) {} friend int AsFriend::getSingleValue();private: int some_member;};int AsFriend::getSingleValue(){ return __a_single.some_member;}

但是作为模板参数就可以编译通过,想来还是因为vector实际是使用了指针的原因。。

class Single;class AsFriend{public: AsFriend():__a_single() {} int getSingleValue();private: std::vector<Single> __a_single;};class Single{public: Single():some_member(42) {} friend int AsFriend::getSingleValue();private: int some_member;};int AsFriend::getSingleValue(){ return __a_single[0].some_member;}

可以用指针去掉这个相互引用的问题Single ~~ Window_mgrAsFriend ~~ Screen

single.h

#include <friend.h>class Single{public: Single(); //由于这里必须知道*AsFriend*的定义,所以上方必须包含`头文件` friend int AsFriend::getSingleValue();private: int some_member;};

single.cpp

Single::Single() :some_member(42){}

friend.h

class Single;class AsFriend{public: AsFriend();~AsFriend(); int getSingleValue();private: Single* __a_single;//声明为指针,只要前置声明一下 Single就可以了};

friend.cpp

#include 'friend.h'#include <single.h> //这包含头文件即可AsFriend::AsFriend() :__a_single(new Single){}AsFriend::~AsFriend(){ delete __a_single;}int AsFriend::getSingleValue(){ return __a_single->some_member;}

test

#include <iostream>#include <friend.h>#include <single.h>namespace friendmeberfunction{ void testMain() {AsFriend onlyme;std::cout <<'I have a friend -> '<<onlyme.getSingleValue()<<std::endl; }}回答2:

程序是没有问题,可以将类的成员函数单独友元,这样只有该成员函数具有对声明对象(Screen)的访问特权。

单独友元类的某个方法必须满足三个条件,就这里的例子而言:

必须先定义Window_mgr类,在类定义中必须声明,但不能定义,clear方法函数

定义Screen类,包括对Window_mgr::clear的友元声明

最后才能定义Window_mgr::clear,函数中可以对Screen进行特权访问

这是C++ Primer原文,我专门用VS2013测试过了,是可以编译通过的。

至于这个问题,一开始我以为是inline的原因,后面实验发现不是。

现在只能想到是VS2013的IntelliSense的问题,毕竟这种写法不多见,该智能感知助手还未学习这种友元某个类函数的方法。

有机会可以在VS2015或其他IDE中实验下。

回答3:

题主的代码在 VS2015 下编译通过,没有问题(使用成员函数友元),并无截图中的错误提示。估计是题主 VS 的 IntelliSence 缓存没有刷新呢吧。

相关文章: