首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >会员朋友功能:“李普曼5号”一书错了吗?

会员朋友功能:“李普曼5号”一书错了吗?
EN

Stack Overflow用户
提问于 2018-03-19 04:29:37
回答 2查看 84关注 0票数 1

利普曼5号ISBN-13: 978-0321714114

第280-281页说:

使成员函数成为朋友 与其让整个Window_mgr类成为朋友,Screen可以指定只允许透明成员访问。当我们声明一个成员函数为朋友时,我们必须指定该函数是其成员的类: 类屏幕{ // Window_mgr::clear必须在类屏幕好友Window_mgr::clear(ScreenIndex)之前声明;// .屏幕类的其余部分}; 让一个成员函数成为朋友需要仔细地构造我们的程序,以适应声明和定义之间的相互依赖。在这个例子中,我们必须按如下顺序排列我们的程序:

  • 首先,定义Window_mgr类,它声明但不能定义清除。在清除之前必须声明屏幕才能使用屏幕的成员。
  • 接下来,定义类屏幕,包括用于清除的朋友声明。
  • 最后,定义clear,它现在可以引用屏幕中的成员。

问题是:类Window_mgr有一个依赖于类屏幕定义的数据成员。请参见:

代码语言:javascript
复制
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, ' ')};
};

因此,如果不事先定义屏幕,就不可能首先定义Window_mgr!同时,如果没有定义Window_mgr,就不可能定义屏幕!

如何解决这个问题?这本书错了吗?

我将在这里粘贴一个代码,以便您可以使用最小的代码重复这个问题:

代码语言:javascript
复制
#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;
}

如果我编译了这段代码,结果是: error:使用未声明的标识符'B‘friend B::hello();

如果反转位置(A <-> B),我有: error:使用未声明的标识符'A‘std::向量x{A(10)};

有正确的方法吗??

谢谢!

编辑:

谢谢,克雷格·杨

解决方案:

代码语言:javascript
复制
#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,例如: A(10);
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-03-19 08:47:36

一开始

好吧,你没有正确地遵循指引。

首先,定义Window_mgr类,它声明但不能定义清除。在清除之前必须声明屏幕才能使用屏幕的成员。

必须在B之前声明A

接下来,定义类屏幕,包括用于清除的朋友声明。

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

最后,定义clear,它现在可以引用屏幕中的成员。

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

在此之前已经讨论过这一点:C++ Forward declaration , friend function problem

你增加了并发症

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

--重要的是要知道,您只有对A的“部分”访问。您不能在A的声明中“充分使用”B。因此,B中的下面一行是错误的。

代码语言:javascript
复制
//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__。

样本代码

代码语言:javascript
复制
#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;
}
票数 1
EN

Stack Overflow用户

发布于 2018-03-19 04:34:11

您必须有更早的声明,而不是更早的定义。

添加

代码语言:javascript
复制
class A;
class B;

前面告诉编译器,“A”和“B”指的是类。这应该足以让它推理出剩下的部分。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49355819

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档