前向声明的问题-Friend函数和行/点类

Problems with forward declaration - Friend functions and line / point classes

本文关键字:点类 函数 -Friend 声明 问题      更新时间:2023-10-16

我有一个演示程序来理解朋友函数。我想,我遇到了与正向声明相关的错误。

我有一个点类,它有x&y坐标。直线类有两个点类对象。现在我在line类中有一个函数,它将计算线的斜率。

这是我的程序:

#include <iostream>
using namespace std;
class point
{
    int x,y;
public:
    point(int,int);
    point();
    friend float line::slope();
};
point::point(int a, int b)
{
    x=a;
    y=b;
}
point::point()
{
}
class line
{
    point p1,p2;
public:
    line(point,point);
    float slope();
};
line::line(point p1, point p2)
{
    this->p1=p1;
    this->p2=p2;
}
float line::slope()
{
    float s;
    s=((float)p2.y-p1.y)/(p2.x-p1.x);
    return s;
}
int main()
{
    float sl;
    point obj(5,10);
    point obj1(4,8);
    line obj3(obj,obj1);
    sl=obj3.slope();
    cout<<"n slope:"<<sl;
    return 0;
}

由于以下原因,它在前向声明方面给了我编译器错误:

  1. 当我尝试首先定义我的线类时,它不知道点类。即使我正向声明点类,这也不足以创建点类的对象,编译器应该知道点类的大小,从而知道整个类本身。通过这个答案中的解释来理解:https://stackoverflow.com/a/5543788

  2. 如果我首先定义点类,它需要知道友元函数的斜率,从而知道类线。因此,在定义点类之前,我尝试为直线类和斜率函数提供如下的正向声明:

等级线;

float line::slope();
class point
{
    int x,y;
public:
    point(int,int);
    point();
    friend float line::slope();
};

现在这给了我以下错误:

friend1.cpp:5: error: invalid use of incomplete type ‘struct line’
friend1.cpp:4: error: forward declaration of ‘struct line’
friend1.cpp:13: error: invalid use of incomplete type ‘struct line’
friend1.cpp:4: error: forward declaration of ‘struct line’
friend1.cpp: In member function ‘float line::slope()’:
friend1.cpp:9: error: ‘int point::y’ is private
friend1.cpp:43: error: within this context
friend1.cpp:9: error: ‘int point::y’ is private
friend1.cpp:43: error: within this context
friend1.cpp:9: error: ‘int point::x’ is private
friend1.cpp:43: error: within this context
friend1.cpp:9: error: ‘int point::x’ is private
friend1.cpp:43: error: within this context

.3.接下来,我试图将point.h和point.cpp中的点类与line.h和line.cpp的行类分离。但这里仍然存在相互依赖关系。

虽然这在理论上应该是可能的,但我不知道如何让它发挥作用。

寻找答案。

谢谢,

Raj

PS:此程序旨在演示单独使用好友功能。当友元函数有两种类型时,这是为了处理第二种类型:

  1. 朋友功能是独立的
  2. 属于另一类的友元函数

因此,在这种情况下,排除了使用友元类的可能性。

line添加为friend,而不仅仅是一个方法:

 friend class line;

其他备注:

  • 将声明与头文件和实现文件中的实现分开
  • using指令相比,更喜欢完全限定(即删除using namespace std;并改用std::cout
  • 更喜欢复杂类型的传递引用-将line(point,point);更改为line(const point&, const point&);

EDIT出于教育目的-您不能像现在的代码那样将特定函数声明为友元,因为line类没有完整的定义。埃尔戈,以下是唯一的方法:

class point;
class line
{
    point *p1,*p2;
public:
    line(point,point);
    float slope();
};
class point
{
    int x,y;
public:
    point(int,int);
    point();
    friend float line::slope();
};

您转发声明point,并将line中的point成员更改为point*(因为点还不是一个完整的类型)。在point中,您现在拥有了line类的完整定义,因此您可以将该方法声明为friend。

编辑2:对于这个特定的场景,不可能在line中使用point对象,因为您需要完整的类型。但是line也必须被完全定义,才能将其成员声明为friend

让Line成为Point 的朋友

class point
{
 friend class line;
 ...
};

将单个方法声明为朋友并没有什么意义。

您可以创建一个辅助函数来计算斜率。这允许您使函子的方法成为point的朋友,而不涉及line

class point;
class line;
struct slope {
    float operator () (const point &, const point &) const;
    float operator () (const line &) const;
};
class point {
    int x,y;
public:
    point(int a,int b) : x(a), y(b) {}
    point() {}
    friend float slope::operator ()(const point &, const point &) const;
};
class line {
    point p1,p2;
public:
    line(point a,point b) : p1(a), p2(b) {}
    float slope() { return ::slope()(*this); }
    friend float slope::operator ()(const line &) const;
};

与实施:

float slope::operator () (const point &p1, const point &p2) const {
    float s;
    s=((float)p2.y-p1.y)/(p2.x-p1.x);
    return s;
}
float slope::operator () (const line &l) const {
    return (*this)(l.p1, l.p2);
}

在正常情况下,我会避免在这里使用friend

倾向于在point:中添加一个函数

float slope_to(const point& other)
{// Not checked, just translated from your implementation
    return ((float)other.y-y)/(other.x-x);
}

并实现:

float line::slope()
{
    return p1.slope_to(p2);
}

这样line就不关心point的实现,并且在实现3D points时也不需要更改。


以下是自由函数(1.):的friend的演示

#include <iostream>
class point
{
    int x, y;
public:
    point(int, int);
    friend std::ostream& operator <<(std::ostream& os, const point& p);
};
std::ostream& operator <<(std::ostream& os, const point& p)
{
    return os << '(' << p.x << ", " << p.y << ')';
}
point::point(int a, int b)
    :x(a)
    ,y(b)
{
}
int main()
{
    point obj(5, 10);
    std::cout << "n point " << obj;
}

下面是一个在您自己的代码上构建的示例,它具有成员函数(2.)的friend

#include <iostream>
#include <memory>
using namespace std;
class point;
class line
{
    std::auto_ptr<point> p1, p2;
public:
    line(point&, point&);
    float slope();
};
class point
{
    int x, y;
public:
    point(int, int);
    friend float line::slope();
};
point::point(int a, int b)
    :x(a)
    ,y(b)
{
}
line::line(point& p1, point& p2)
    :p1(new point(p1))
    ,p2(new point(p2))
{
}
float line::slope()
{
    return ((float)p2->y - p1->y) / (p2->x - p1->x);
}
int main()
{
    point obj(5, 10);
    point obj1(4, 8);
    line obj3(obj, obj1);
    cout << "n slope:" << obj3.slope();
}

为了从line中引用point,我使用(auto_)指针和引用,因为类在该点被声明,而不是定义。CCD_ 31被及时声明,以便我将其引用为CCD_ 33的CCD_。这种循环依赖是一种可怕的代码气味,应该避免。

在定义类之前,您引用了friend float line::slope();中的行类。

只需在点类的定义之前添加线class line;

也将friend float line::slope();更改为friend class line;