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

全部回覆(3)
巴扎黑

其實是因為類別互相引用產生的錯誤。 。
單獨宣告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;
    }
}
大家讲道理

程式是沒有問題,可以將類別的成員函數單獨友元,這樣只有該成員函數具有對宣告物件(Screen)的存取特權。

單獨友元類別的某個方法必須滿足三個條件,就這裡的例子而言:

  1. 必須先定義Window_mgr類,在類別定義中必須聲明,但不能定義,clear方法函數

  2. 定義Screen類,包括對Window_mgr::clear的友元聲明

  3. 最後才能定義Window_mgr::clear,函數中可以對Screen進行特權存取

這是C++ Primer原文,我專門用VS2013測試過了,是可以編譯通過的。

至於這個問題,一開始我以為是inline的原因,後面實驗發現不是。

現在只能想到是VS2013的IntelliSense的問題,畢竟這種寫法不多見,該智能感知助手還未學習這種友元某個類函數的方法。

有機會可以在VS2015或其他IDE中實驗下。

PHPzhong

題主的程式碼在 VS2015 下編譯通過,沒有問題(使用成員函數友元),並無截圖中的錯誤提示。估計是題主 VS 的 IntelliSence 快取沒有刷新呢。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板