2015-11-06 74 views
0

我有两个类之间的朋友函数的问题。让我们来看看一些代码:朋友函数和包含循环

第一类:

#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 

是没有问题的,如果我试图让友元类。如果我像上例中的朋友FUNCTION一样发生问题。 我可以通过#include“Second.h”在First class中解决这个问题,但它会包含循环。你有什么想法如何做到这一点?

+0

'#include'循环没有问题,不是当你用'#ifndef _FIRST_H_' –

+3

@MadsMarquart启动它们时,不是这样。这将是一个问题。 –

+0

另外,我不明白你为什么想要这样做?检索字符串似乎很没用。 –

回答

0

你有什么想法如何做到这一点?

你不能使用friend机制来做你正在尝试的。

一个简单的解决方案是通过成员函数公开First::str,而不用担心friend结构。这是一个更清晰的解决方案。

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

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

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

为什么?如果我可以使用朋友CLASS,那么为什么我不能使用朋友FUNCTION机制? – QueUe

+1

@QueUe,根据我的经验,使用“朋友”机制是最后的选择 - 无论你是上课还是作为“朋友”。这是类间紧密耦合的症状。通过让'Second'成为'First'的朋友,你已经使'Second'与'First'的内部紧密结合了。 'First'不能在没有咨询'Second'的情况下自由地改变它的内部。 –

+0

不幸的是,这是我编程课程的作业。我必须使用朋友功能:) – QueUe

1

问题occures如果我交朋友的功能就像在上面的例子。

// #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构造,现在还是个未知数。 A 指针或参考会没事的。
    • 由于使用了指针或引用,因此也应修改**构造函数。
  3. 定义类别First与朋友声明fun()
  4. 定义fun()

代码对你的例子,改装基地,

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; } 
0

这是不可能的声明一个成员函数作为一个朋友,除非完整的类定义可见。否则允许任意代码声明和定义该类的创建者不打算的类的成员。

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

     void fun(); 
}; 

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

这样做的结果是,First不能简单地是Second成员。为了接受这一点,编译器需要知道Second的完整定义,以便编译First的定义,但也需要知道要编译的Second定义的完整定义First。这是一种无限递归的依赖关系,这往往会打乱编译器。

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

所以,这将工作

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的朋友,并且完成它。毕竟,将类的一个成员函数声明为朋友声明,成员函数将始终按照预期工作。在极少数情况下,可以相信一个类的单个成员函数按照需要工作,但不相信同一类的其他成员函数。

+0

它出现了一系列的编辑提议,并在过去的24小时内被其他成员拒绝我的回答。我最后的编辑实际上是由Chao Mai提出的,旨在纠正一些错误,因为出于某种原因,我没有权力接受(如我所愿)或拒绝他们。 – Peter