朋友功能 - 声明顺序

Han*_*lse 3 c++ header-files friend-function

我有两个叫做Screen和的 课程Window_mgr.

Screen允许Window_mgr通过friend函数声明修改其私有/受保护成员.

结果Window_mgr在代码的最后定义了一个非成员函数Window_mgr::clear,该函数应该使用它.

不幸的是,我得到了一些荒谬的错误,我无法解释.

我错过了什么?

在此输入图像描述

Screen.h

#pragma once

#ifndef SCREEN_H
#define SCREEN_H

#include <string>
#include <vector>

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, ' ') };
};

class Screen {

public:

    // Friends
    friend void Window_mgr::clear(ScreenIndex);
    //friend class Window_mgr;

    // Fields
    // typedef => creates an alias
    // typedef std::string::size_type pos;
    // alternative way to declare a type member using a type alias
    using pos = std::string::size_type;

    // Constructors
    Screen() = default; // needed because Screen has another constructor
                        // cursor initialized to 0 by its in-class initializer
    Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c) {} // get the character at the cursor
    Screen &display(std::ostream &os) // function is in the class body => implicitly inline
    {
        do_display(os);
        return *this;
    }
    const Screen &display(std::ostream &os) const // function is in the class body => implicitly inline
    {
        do_display(os);
        return *this;
    }

    // Methods
    char get() const { return contents[cursor]; } // implicitly inline
    inline char get(pos ht, pos wd) const; // explicitly inline
    Screen &move(pos r, pos c); // can be made inline later
    Screen &set(char);
    Screen &set(pos, pos, char);

private:
    // Fields
    mutable size_t access_ctr;
    pos cursor = 0;
    pos height = 0, width = 0;
    std::string contents;

    // Methods
    void do_display(std::ostream &os) const { os << contents; }
};

inline Screen &Screen::set(char c)
{
    contents[cursor] = c; // set the new value at the current cursor location
    return *this; // return this object as an lvalue
}

inline Screen &Screen::set(pos r, pos col, char ch)
{
    contents[r*width + col] = ch; // set specified location to given value
    return *this; // return this object as an lvalue
}

// we can specify inline on the definition
inline Screen &Screen::move(pos r, pos c) {
    pos row = r * width; // compute the row location
    cursor = row + c; // move cursor to the column within that row
    return *this; // return this object as an lvalue
}

char Screen::get(pos r, pos c) const // declared as inline in the class
{
    pos row = r * width; // compute row location
    return contents[row + c]; // return character at the given column
}

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.contents = string(s.height * s.width, ' ');
}

#endif
Run Code Online (Sandbox Code Playgroud)

das*_*ght 5

您不能ScreenWindow_mgr类中声明对象的向量,因为Screen编译器在代码中不知道它.如果要声明指针向量,可以通过向前声明来修复它Screen,但对于实际对象的向量,必须提供完整定义.

你需要切换Window_mgr和的顺序,Screen并向Window_mgr类声明友谊:

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, ' ') };
};
Run Code Online (Sandbox Code Playgroud)

为什么编译器知道Window_mgr但不知道Window_mgr::ScreenIndex

C++对友谊声明中使用的类名有一个特殊规则:

如果尚未声明友元声明中使用的类的名称,则会在现场进行前向声明.

这就是编译器"知道"的方式Window_mgr(即它没有;它接受你的话).对于在"befriended"类中声明的成员函数或成员类型,没有这样的规则.这就是编译器不知道的原因Window_mgr::ScreenIndex.