朋友功能和包含循环

时间:2015-11-06 21:59:04

标签: c++ friend-function friend-class

我的两个班级之间的朋友功能有问题。让我们看一些代码:

头等舱:

#ifndef _FIRST_H_
#define _FIRST_H_

//#include "Second.h"
#include <string>

class Second;
class First
{
    friend void Second::fun();

    std::string str = "Dziala\n";
public:
    First();
    ~First();
};
#endif

和第二课:

#ifndef _SECOND_H_
#define _SECOND_H_

#include<iostream>
#include "First.h"

class Second
{
    First fObj;
public:
    Second();
    ~Second();
    void fun() { std::cout << fObj.str; }
};
#endif 

如果我想交朋友CLASS,没有问题。如果我像上面的例子中那样建立朋友FUNCTION,就会出现问题。 我可以通过First类中的#include“Second.h”来解决这个问题,但接下来它将是include循环。你知道怎么做吗?

3 个答案:

答案 0 :(得分:2)

  

如果我像上面的例子那样交朋友FUNCTION,就会出现问题。

// #include "Second.h"
#include <string>

class Second;
class First
{
    friend void Second::fun();
...

第一行是类Second的声明。这是前瞻声明。对于课程Second,在其声明之后及其定义之前,它是不完整类型。因此Second被称为类类型,但它包含的成员是未知的。所以你不能在这里使用成员void Second::fun()

friend class Second工作正常,因为它从不尝试使用不完整类型的成员。

  

然后它将是包含循环。

正如MadsMarquart所说,这不是问题,因为你已经有了头球卫士。

  

知道怎么做吗?

如果您想使用friend void Second::fun()作为朋友声明,声明和定义的顺序很重要,只需对您的课程进行一些修改。

  1. 声明课程First
  2. 使用<{> Second声明(非定义)定义课程fun()
    • 您现在无法使用First fObj成员或尝试new First,因为First未定义且First的构造函数现在未知。 指针或引用就可以了。
    • 由于使用了指针或引用,因此也应该修改**构造函数。
  3. 使用朋友声明First定义班级fun()
  4. 定义fun()
  5. 根据您的示例修改代码,

    class First;
    
    class Second {
     public:
      Second(First& rfObj) : fObj(rfObj) {}
      void fun();
    
     private:
      First& fObj;
    };
    
    class First {
      friend void Second::fun();
     public:
      First() = default;
    
    private:
      std::string str = "Dziala\n";
    };
    
    void Second::fun() { std::cout << fObj.str; }
    

答案 1 :(得分:0)

  

你知道怎么做吗?

您无法使用friend机制来执行您正在尝试的操作。

一个简单的解决方案是通过成员函数公开First::str,而不用担心friend构造。从长远来看,这是一个更清洁的解决方案。

class First
{
  public:
    First();
    ~First();

    std::string const& getString() const { return str; }

  private:
    std::string str = "Dziala\n";
};

答案 2 :(得分:0)

除非完整的类定义可见,否则无法将成员函数声明为朋友。否则允许任意代码声明和定义该类的创建者不想要的类的成员。

class Second     // complete class definition, not just a forward declaration
{
    public:

       void fun();
};

class First
{
    friend void Second::fun();
};

这样做的结果是First不能仅仅是Second的成员。为了接受这一点,编译器需要具有Second的完整定义的可见性,以便编译First的定义,同时还可以查看First的完整定义以获得定义Second编译。这是一种无限递归的依赖,这往往会扰乱编译器。

只能使用前向声明声明的类成员(或实际上通常是变量)的唯一类型是指针或引用。

所以,这会起作用

class First;

class Second     // complete class definition, not just a forward declaration
{
    private:
        First &fObj;    // note this is a reference
    public:

       void fun();

       Second();
       ~Second();
};

class First
{
    friend void Second::fun();
};

Second::Second() : fObj(*(new First))   // assumes First has appropriate (not shown) constructor
{}

Second::~Second()
{
   delete &fObj;
}

但是,请注意,Second的构造函数和析构函数也不能编译,除非First的定义事先对编译器可见。这是因为不可能仅基于前向声明来创建或销毁类类型的实例(即与原始问题相同的原因)。

实际上,我只是宣布班级SecondFirst的朋友并完成它。毕竟,将一个类的一个成员函数声明为朋友断言,将始终实现成员函数以按预期工作。在极少数情况下,可以信任类的单个成员函数按要求工作,但不信任同一类的其他成员函数。