【问题标题】:C++ friend classes and friend member functionsC++友元类和友元成员函数
【发布时间】:2017-06-28 15:14:58
【问题描述】:

我正在学习 C++ 类中的友元函数、友元类和友元成员函数; 现在,以下代码可以正常编译:

#include <iostream>

class A 
{
public:
    friend class B;
    //friend void B::set(int i);
    //friend int B::get();
    friend int function(A a);
    A(int i);
    void set(int i);
    int get();
private:
    int i;
};

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

void A::set(int i)
{
    this->i = i;
}

int A::get()
{
    return i;
}

class B
{
public:
    B(A a);
    void set(int i);
    int get();
private:
    A a;
};

B::B(A a) : a(a)
{
}

void B::set(int i)
{
    a.i = i;
}

int B::get()
{
    return a.i;
}

int function(A a);

int main(int argc, char *argv[])
{
    A a(0);
    std::cout << "in A i=" << a.get() << std::endl;
    a.set(10);
    std::cout << "in A i=" << a.get() << std::endl;
    B b(a);
    std::cout << "in B i=" << b.get() << std::endl;
    b.set(21);
    std::cout << "in B i=" << b.get() << std::endl;
    std::cout << "function returns " << function(a) << std::endl;
}

int function(A a)
{
    return a.i;
}

我能够授予 B 类友谊并在 A 类中执行“函数”,而无需前向声明 B 类或函数“函数”。 现在,如果我想为 B 类中的两个成员函数授予友谊,如果我在定义 A 类之前不定义 B 类,则它不起作用:

#include <iostream>

class B;   // doesn't work, incomplete type (complete type needed)

class A 
{
public:
    //friend class B;
    friend void B::set(int i);
    friend int B::get();
    friend int function(A a);
    A(int i);
    void set(int i);
    int get();
private:
    int i;
};

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

void A::set(int i)
{
    this->i = i;
}

int A::get()
{
    return i;
}

B::B(A a) : a(a)
{
}

void B::set(int i)
{
    a.i = i;
}

int B::get()
{
    return a.i;
}

int function(A a);

int main(int argc, char *argv[])
{
    A a(0);
    std::cout << "in A i=" << a.get() << std::endl;
    a.set(10);
    std::cout << "in A i=" << a.get() << std::endl;
    B b(a);
    std::cout << "in B i=" << b.get() << std::endl;
    b.set(21);
    std::cout << "in B i=" << b.get() << std::endl;
    std::cout << "function returns " << function(a) << std::endl;
}

int function(A a)
{
    return a.i;
}

但我无法在定义 A 类之前定义 B 类,所以我被卡住了。前向声明(不定义)B 类也不起作用。

所以我的问题是:

1) 为什么我不需要在友谊声明中转发声明一个函数或整个类,但如果我需要指定该类的成员函数,我确实需要定义一个类? 我知道友谊声明不是常识中的声明(它们只是授予访问权限,而不是转发声明任何内容)。

2) 我怎样才能使我的代码编译(除了将 B 中的 A 成员对象声明为 A *a)?

【问题讨论】:

  • 其实不需要把B类的成员函数声明为友元函数,因为A类有公共接口。
  • @VladfromMoscow 这确实是一个人为的例子。我只是想了解它为什么不起作用以及如何解决这个问题。
  • “我不能在定义 A 类之前定义 B 类”为什么?
  • @Luca 不起作用,因为编译器不知道B类是否确实有这些成员函数。
  • @n.m.实际上它确实有意义

标签: c++ class friend


【解决方案1】:

这里是一个朋友类的例子以及如何使用它。这是cplusplus.com 我发布这个的原因是因为你的例子并没有真正说明在 c++ 中正确使用友谊。我希望这将阐明您应该如何/为什么使用友谊,这可以帮助您解决前向声明问题。

// friend class
#include <iostream>
using namespace std;

class Square;

class Rectangle {
    int width, height;
  public:
    int area ()
      {return (width * height);}
    void convert (Square a);
};

class Square {
  friend class Rectangle;
  private:
    int side;
  public:
    Square (int a) : side(a) {}
};

void Rectangle::convert (Square a) {
  width = a.side;
  height = a.side;
}

int main () {
  Rectangle rect;
  Square sqr (4);
  rect.convert(sqr);
  cout << rect.area();
  return 0;
}

在这个例子中,类 Rectangle 是类 Square 的朋友,允许 Rectangle 的成员函数来访问私有成员和受保护成员 广场。更具体地说, Rectangle 访问成员变量 Square::side,描述正方形的边。

在这个例子中还有一些新的东西:在 程序中,有一个 Square 类的空声明。这是 必要的,因为类 Rectangle 使用 Square (作为参数 成员转换),Square 使用 Rectangle(将其声明为朋友)。

除非指定,否则友谊永远不会对应:在我们的示例中, 矩形被 Square 视为朋友类,但 Square 不是 被 Rectangle 视为朋友。因此,成员函数 Rectangle 可以访问 Square 的受保护成员和私有成员,但是 不是相反。当然,也可以声明 Square Rectangle 的朋友(如果需要)授予此类访问权限。

友谊的另一个属性是它们不能传递: 朋友的朋友不被视为朋友,除非明确表示 指定。

【讨论】:

    【解决方案2】:

    只需让class B 成为class A 的朋友。这样做不会产生不利影响。

    如果您绝对想要进行更细粒度的控制,您可以使用这样的代理类来实现(使用您的示例剥离到裸露的骨骼):

    class Proxy;
    
    class A
    {
    public:
        friend class Proxy;
        A(int i);
    private:
        int i;
    };
    
    class B
    {
    public:
        B(A a);
        void set(int i);
        int get();
    private:
        A a;
    };
    
    class Proxy
    {
      friend void B::set(int);
      friend int B::get();
      static int& get_i(A& a) { return a.i; }
      static const int& get_i(const A& a) { return a.i; }
    };
    

    您现在可以在B::setB::get 中使用Proxy::get_i(a) 代替a.i(仅限)。

    【讨论】:

    • 在这种情况下,我什至不需要 Proxy 类前向声明​​
    猜你喜欢
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2015-12-30
    • 2013-07-25
    相关资源
    最近更新 更多