c++ - cpp primer 5th 练习7.32(关于友元函数的问题)
PHP中文网
PHP中文网 2017-04-17 13:29:36
0
3
636
#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中文网

认证高级PHP讲师

reply all(3)
巴扎黑

In fact, it is an error caused by classes referencing each other. .
There is no problem in declaring Window_mgr alone as a member of Screen, but if you use member functions, you will find the definition of the class, and your Window_mgr also contains members of Screen, so the compiler will be confused. I think It may also be an implementation problem, although the same is true for the gcc I use. .

I found that the following code will not compile at all

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;
}

But it can be compiled and passed as a template parameter. It is probably because vector actually uses pointers. .

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;
}

You can use pointers to get rid of this mutual reference problem
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;
    }
}
大家讲道理

There is no problem with the program. You can make the member functions of the class a separate friend, so that only the member function has access privileges to the declared object (Screen).

A method of a separate friend class must meet three conditions. In the example here:

  1. The Window_mgr class must be defined first. It must be declared in the class definition, but cannot be defined. The clear method function

  2. Define the Screen class, including the friend declaration for Window_mgr::clear

  3. Finally Window_mgr::clear can be defined, and the function can provide privileged access to Screen

This is the original text of C++ Primer. I have tested it with VS2013 and it can be compiled and passed.

As for this problem, at first I thought it was due to inline, but later experiments revealed that it was not.

Now I can only think that it is a problem with IntelliSense in VS2013. After all, this writing method is rare, and the intelligent sensing assistant has not yet learned this method of friending a certain class function.

If you have the opportunity, you can experiment in VS2015 or other IDEs.

PHPzhong

The subject's code was compiled and passed under VS2015, with no problems (using member function friends), and there was no error message in the screenshot. It may be that the IntelliSence cache of the subject VS is not refreshed.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template