【问题标题】:Member Function as Friend: Is the book Lippman 5th wrong?Member Function as Friend:Lippman 5th 这本书错了吗?
【发布时间】:2018-08-27 14:11:25
【问题描述】:

李普曼 5th ISBN-13:978-0321714114

第 280-281 页,上面写着:

让成员函数成为朋友

与其让整个 ​​Window_mgr 类成为朋友,Screen 可以 而是指定只允许 clear 成员访问。什么时候我们 声明一个成员函数为友元,我们必须指定类 该函数是哪个成员:

class Screen {
    // Window_mgr::clear must have been declared before class Screen
    friend void Window_mgr::clear(ScreenIndex);
    // ... rest of the Screen class
};

使成员函数成为朋友需要仔细构造我们的 适应宣言和宣言之间相互依存关系的计划 定义。在这个例子中,我们必须按如下顺序排列我们的程序:

  • 首先,定义Window_mgr 类,它声明但不能定义clear。必须在 clear 之前声明 screen 才能使用 Screen 的成员。
  • 接下来,定义类 Screen,包括一个用于 clear 的友元声明。
  • 最后定义clear,现在可以引用Screen中的成员了。

问题是:类 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, ' ')};
};

所以不定义Screen就不可能先定义Window_mgr 之前! 同时,如果没有我们定义 Screen 是不可能的 定义了Window_mgr!!!

这个问题怎么解决??? 书错了吗?

我将在此处粘贴一个代码,以便您可以使用 最少的代码:

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

class A
{
    friend void B::hello();

public:
    A(int i) : number{i} {}

private:
    void f() {
        std::cout << "hello" << std::endl;
    }
    int number;
};

class B {
private:
    std::vector<A> x{A(10)};

public:
    void hello()
    {
        for(A &elem : x)
        {
            elem.f();
        }
    }
};


int main()
{
    A x;

    return 0;
}

如果我编译这段代码,结果是: 错误:使用未声明的标识符“B” 朋友 void B::hello();

如果我反转位置(A B),我有: 错误:使用未声明的标识符“A” std::vector x{A(10)};

有正确的方法吗?

谢谢!


编辑:

谢谢你,克雷格·杨

解决方案:

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

class A;

class B {
private:
    std::vector<A> x;

public:
    B();
    void hello();

};

class A
{
    friend void B::hello();

public:
    A(int i) : number{i} {}

private:
    void f() {
        std::cout << "hello" << std::endl;
    }
    int number;
};

B::B() : x{A(10)}
{

}

void B::hello()
{
    for(A &elem : x)
    {
        elem.f();
    }
}

int main()
{


    return 0;
}

结论:

  • 这本书是不完整的,因为它没有揭示首先进行 A 类的前向声明的必要性,以及在这种情况下不可能进行类内初始化。
  • 我没有注意到问题是 A(10),而不是向量!也就是说,当我们将它用作向量的模板参数时,我们可以使用不完整类型 A(仅声明,没有定义)(因为它本身不会创建 A 对象),但在定义对象时不能使用不完整类型 A,例如:A(10);

【问题讨论】:

    标签: c++


    【解决方案1】:

    你必须有一个更早的声明,而不是一个更早的定义

    添加

    class A;
    class B;
    

    在前面告诉编译器“A”和“B”指的是类。这应该足以推理出其余部分。

    【讨论】:

    • 此解决方案不起作用:错误:在嵌套名称说明符朋友 void B::hello() 中命名的类型“B”不完整;
    • 在 A/B 示例中除了无朋友之外还有其他问题,因为您包含了方法的主体,因此您需要实现细节而不仅仅是类签名。这就是为什么类通常在头文件中定义其签名的原因。
    • 如果我删除方法的主体,我仍然有数据成员 std::vector x{A(10)} 来解决。本书忽略了这个问题。
    • 数据成员本身很好,核心调用是给它一个循环引用的值。将它放在类签名之后提供的 ctor 主体中。
    【解决方案2】:

    首先

    嗯,你没有正确遵循指导。

    首先,定义 Window_mgr 类,它声明但不能定义 clear。必须先声明 Screen,clear 才能使用 Screen 的成员。

    您必须在A 之前声明B

    接下来,定义类 Screen,包括一个用于 clear 的友元声明。

    现在声明AB::hello() 为好友。

    最后定义clear,现在可以引用Screen中的成员了。

    B:hello()可以使用A的私有成员。

    这里之前已经介绍过:C++ Forward declaration , friend function problem

    你增加了复杂性

    此外,您希望 B 的声明引用 A。为此,您需要转发声明A,以便B 知道它的存在。

    并且请务必注意,您对A 仅有“部分”访问权限。您不能在 B 的声明中“完全使用”A。所以B下面这行是错误的。

    //You're trying to create A when you only know it exists.
    //You don't have a full definition of A yet.
    std::vector<A> x{A(10)};
    
    //Replace the above with...
    std::vector<A> x;
    

    当然你必须找到另一种方法来初始化x


    示例代码

    #include <iostream>
    #include <vector>
    
    class A;
    
    class B
    {
    private:
        std::vector<A> x;
    public:
        void hello();
    };
    
    class A
    {
        friend void B::hello();
    public:
        A(int i): number(i) {}
    
    private:
        void f() { std::cout << "hello" << std::endl; }
        int number;
    };
    
    void B::hello()
    {     
        for(A &elem : x)
        {
            elem.f();
        }
    }
    
    int main()
    {
        A a{5};
        return 0;
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-31
    • 2012-09-22
    • 1970-01-01
    相关资源
    最近更新 更多