1、Link Error 和 Compile Error
1) Link阶段发生的错误(文件本身complie没有问题,但是互相链接阶段的问题。例如声明了函数但是没有找到主体、库文件的错误以及互相引用的问题等。)
*error以LNK开头
2) Complie阶段的问题。(某个文件本身的问题,可能是语法等)
error以C开头
2、头文件中函数定义:使用inline 或者 static
#include相当于复制过去,如果在一个头文件A.h中定义函数B,其他多个文件都使用了#include"A.h",那B函数就会出现多次定义的LNK错误。(always have a body in xx,but… )
解决办法:
1)只在头文件中写函数声明,函数body写入其他函数。
2)在函数前加static,相当于该函数为本文件私有使用,不对外可见。所有使用该函数的文件相当于都单独拥有一份该函数的内部定义。
3)在函数前加inline,内联函数相当于直接在函数引用中替换值。
3、Inline 内联函数
- 隐式内联、显式内联
定义在类内的函数都是隐式内联函数,显示内联需要增加关键字inline
**隐式内联**
using namespace std;
class A
{
public:
void func(int x,int y){i=x;j=y;} //成员函数func()是内联函数
void print(){cout<<"两数相乘为:"<<i*j<<endl;} //成员函数print()是内联函数
private:
int i,j;
};
int main()
{
A a;
a.func(1,2); //调用func(1,2)内联函数等于直接将i=1,j=2写在这里
a.print(); //调用print()内联函数等于将"cout<<"两数相乘为:"<<i*j<<endl;"直接写到该行
return 0;
}
2)不是所有的函数都适合定义为inline,因为inline是以代码复制、即增加内存消耗为代价换取代码运行速度的(无需调用函数而是直接复制替换)。
①使用次数过多的,每次都复制,内存消耗量++
②本身inline函数中消耗就较大的,不适合。比如当内部有循环体时,执行函数体的循环要比调用函数的花销更大。
参考:inline那些事
4、C++类型转换及其!!极其!!不智能
一定要注意数据类型不同时的转换丢失情况。bool 、int、float、double它是一点不会转!!!
另外,注意output里面warning的信息,很可能就是最后导致error的地方!没报错是因为语法上对,逻辑上和实际严格检查上不一定对。
编译器报错的滞后性:
很可能报错在n行,实际出错在n-1行,报错位置比真正出错的位置滞后一行。
例如:在第7行缺少分号,但在编译第8行时才会发现第7行有错,因此报错在8行。记得debug时检查上一行内容。
5、判断点是否在三角形内部
法1:一般程序都用同侧法,即将三角形三边看作有方向的AB、BC、CA,看Q点是否在三条边的同侧。
新的问题,如何判断两个点在一条线的同侧?——右手螺旋定则!
根据向量的叉乘以及右手螺旋定则,ABxAM (x表示叉乘,这里向量省略了字母上面的箭头符号)的方向为向外指出屏幕,ABxAN也是向外指出屏幕,但ABxAO的方向是向内指向屏幕,因此M,N在直线AB的同侧,M ,O在直线AB的两侧。实际计算时,只需要考虑叉积的数值正负。
假设以上各点坐标为A(0,0), B(4,0), M(1,2), N(3,4), O(3,-4), 则:
ABxAM = (4,0)x(1,2) = 42 - 01 = 8
ABxAN = (4,0)x(3,4) = 44 – 03 = 16
ABxAO = (4,0)x(3,-4) = 4*-4 – 0*3 = –16
回到三角形内外的判断中来,以Q点图为例。判断Q点:
flag1=ABxAQ
flag2=BCxBQ
flag3=CAxCQ
3个flag同号则在内部,异号则在外部。
PS:点乘(意义是cos)可以用于判断角度是否大于90°,大于为负,小于为正
//ours_1
static bool insideTriangle(int x, int y, const Vector3f* _v)
{
// TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
//p
Eigen::Vector3f v0p = { _v[0].x() - x,_v[0].y() - y,1.0f };
Eigen::Vector3f v1p = { _v[1].x() - x,_v[1].y() - y,1.0f };
Eigen::Vector3f v2p = { _v[2].x() - x,_v[2].y() - y,1.0f };
//v
Eigen::Vector3f v0v1 = { _v[0].x() - _v[1].x(),_v[0].y() - _v[1].y(),1.0f };
Eigen::Vector3f v1v2 = { _v[1].x() - _v[2].x(),_v[1].y() - _v[2].y(),1.0f };
Eigen::Vector3f v2v0 = { _v[2].x() - _v[0].x(),_v[2].y() - _v[0].y(),1.0f };
float flagv0v1 = v0p.cross(-v2v0).z();
float flagv1v2 = v1p.cross(-v0v1).z();
float flagv2v0 = v2p.cross(-v1v2).z();
if (flagv0v1>0) {
return flagv1v2>0 && flagv2v0>0;
}
else {
return flagv1v2<0 && flagv2v0<0;
}
}
法2:自向量乘法,其实跟上一个方法的核心思想一样,但是计算量小,中间变量也更小
flag1=QAxQB
flag2=QBxQC
flag3=QCxQA
同号内部,异号外部
static bool insideTriangle(int x, int y, const Vector3f* _v){
Eigen::Vector3f pv0 = { x - _v[0].x() ,y- _v[0].y() ,1.0f };
Eigen::Vector3f pv1 = { x - _v[1].x() ,y - _v[1].y() ,1.0f };
Eigen::Vector3f pv2 = { x - _v[2].x() ,y - _v[2].y() ,1.0f };
if (pv0.cross(pv1).z()>0 ) {
return pv1.cross(pv2).z() > 0 && pv2.cross(pv0).z() > 0;
}
else {
return pv1.cross(pv2).z() < 0 && pv2.cross(pv0).z() < 0;
}
}