今日写题又遇新bug,先上题目:
设计用于表示点、线和三角形的类:Point、Line和Triangle,要求如下:
(1)Point类中包含两个用于表示点的X和Y坐标分量的公有数据成员,能够根据指定的X和Y
坐标构建点对象。
(2)Line类中包含两个用于表示线段端点的私有对象成员,能够根据指定的两点构造线段
对象(要求构造函数的参数为常引用),具有计算线段长度的公有成员函数。
(3)Triangle类中包含三个用于表示三角顶点的私有对象成员,能够根据指定的三点构造
三角形对象(要求构造函数的参数为常引用),具有计算三角形周长和面积的公有成员函
数。
在main函数中:
根据输入的三个点的坐标构建三角形对象,并输出的三角形的周长和面积。
对于要求(1),我只创建了相应的构造函数
class Point{
friend class Line;
friend class Triangle;
private:
double x;
double y;
public:
Point(double X,double Y)
{
x=X;
y=Y;
}
};
之后就去写剩下两个类
class Line{
private:
Point p1;
Point p2;
...
};
class Triangle{
private:
Point a;
Point b;
Point c;
...
};
写完main函数中的内容后,我编译运行,出现很多错误。因为编译的错误往往一环扣一环,所以这种时候只需要去看第一条报错;并且因为往往第一个出现错误的语句会影响编译器对之后代码的编译,所以往往只有第一条错误是靠谱的。
no matching function for call to ‘Point::Point()’ 的意思是Point域名下没有叫做Point()的函数。35行是空代码,下面的语句不涉及构造函数不会有错,那只能是上面的语句有错了,34行执行的是地址值传递,也不应该有错,所以只能是31行、32行的语句错了,因此这个情形下编译器会自行调用默认构造函数。我想起之前学过的关于构造函数的知识:编译器会自动为类提供构造函数及析构函数,但是是有条件的。
具体规则如下:
默认情况下,C++编译器至少给一个类添加3个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数,对传入对象属性进行值拷贝
如果用户定义有参构造函数,C++不再提供默认无参构造函数,但会提供默认拷贝构造函数;
如果用户定义拷贝构造函数,C++不再提供其他构造函数。
这个结论咋一看不好记,其实可以用图形化的方法记忆。
这个顺势而下的依据是函数的复杂度,这个规则可总结为,用户提供了什么,C++就不再提供之前的了(用户既然已经提供了当前复杂度的构造函数,在此之前的构造函数复杂度更低,那么用户更有能力自己设置好,故只为用户提供比当前复杂度更高的构造函数)。不过值得注意的是,用户提供无参构造函数时,C++只会提供默认拷贝构造函数。
在发现我的错误后我在Point类内增加了无参构造函数
class Point{
friend class Line;
friend class Triangle;
private:
double x;
double y;
public:
Point(double X,double Y)
{
x=X;
y=Y;
}
Point()
{}
}
问题终于解决了。
一点题外话:
1.友元声明可以写在类内任何位置;
2.友元类要先定义才能在要添加友元关系的类中声明(非成员函数可以不这样),例如
class B;
class A{
friend class B;
...
}
3.友元声明最稳定的写法:friend 完整的声明语句;
friend 返回值类型 函数名(参数列表);
friend class 类名;
虽然C++11支持’friend 类名;'的写法,但还是最好不用,因为有的平台可能会不认。