首页  >  问答  >  正文

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

#include <string>
#include<iostream>
#include<vector>

//test 7.32
class 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);

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

PHP中文网PHP中文网2765 天前609

全部回复(3)我来回复

  • 巴扎黑

    巴扎黑2017-04-17 13:31:36

    其实是因为类相互引用产生的错误。。
    单独声明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_mgr
    AsFriend ~~ 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;
        }
    }

    回复
    0
  • 大家讲道理

    大家讲道理2017-04-17 13:31:36

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

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

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

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

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

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

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

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

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

    回复
    0
  • PHPz

    PHPz2017-04-17 13:31:36

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

    回复
    0
  • 取消回复