模板分文件编写
一般的文件,函数的声明放在 .h文件里,函数的实现放在.cpp文件里《包含头文件》,主函数也放在.cpp文件里,
函数的声明文件(.h)被主函数的.cpp文件包含。
一般分文件实例
point.h 头文件一
#pragma once //头文件一般要写这句话,防止编译器重复编译。类似于C的#define __XXX_H ...
#include <iostream> //接下来这两句是套路,基本都要这么写,因为下面会用到这些东西
using namespace std;
class Point{
private:
int px; //点的横坐标
int py; //点的纵坐标
public:
void setX(int x); //设置点的横坐标
void setY(int y); //设置点的纵坐标
int getX(void); //获取点的横坐标
int getY(void); //获取点的纵坐标
};
cpp文件一
point.cpp《包含头文件》
#include "point.h"
void Point::setX(int x)
{
px = x;
}
void Point::setY(int y)
{
py = y;
}
int Point::getX(void)
{
return px;
}
int Point::getY(void)
{
return py;
}
头文件二 circle.h
#pragma once
#include <iostream>
using namespace std;
#include "point.h"
class Circle{
private:
int c_radius;
Point p_center;
public:
void setCRadius(int r);
int getCRadius(void);
void setPCenter(Point p);
Point getPCenter(void);
//判断点是否在圆内
void isPointInnerCircle(Point p);
};
cpp文件《包含circle.h文件》
#include "circle.h"
void Circle::setCRadius(int r)
{
c_radius = r;
}
int Circle::getCRadius(void)
{
return c_radius;
}
/**
* 设置圆心,圆心是类Point
*/
void Circle::setPCenter(Point p)
{
p_center = p; //类和基础类型一样,也可以直接赋值
}
Point Circle::getPCenter(void)
{
return p_center;
}
void Circle::isPointInnerCircle(Point p)
{
//计算点到圆心的距离的平方
int p_distance = (p.getX() - p_center.getX())*(p.getX() - p_center.getX()) +
(p.getY() - p_center.getY())*(p.getY() - p_center.getY());
int r_distance = c_radius * c_radius;
cout << "r_distance = " << r_distance << endl;
cout << "p_distance = " << p_distance << endl;
if(p_distance == r_distance)
{
cout << "Point is on circle round!" << endl;
}else if(p_distance < r_distance)
{
cout << "Point is inner circle!" << endl;
}
else
{
cout << "Point is out circle!" << endl;
}
}
main.cpp《包含两个头文件,cpp不能包含cpp》
#include <iostream>
#include "point.h"
#include "circle.h"
using namespace std;
void test01(void)
{
Point p1; //圆周上
p1.setX(10);
p1.setY(10);
Point p2; //圆外
p2.setX(10);
p2.setY(11);
Point p3; //圆内
p3.setX(10);
p3.setY(9);
Circle c;
//设置圆心坐标
Point p_c;
p_c.setX(10);
p_c.setY(0);
//设置半径
c.setCRadius(10);
//设置圆心
c.setPCenter(p_c);
//判断点和圆的关系
cout << "/*****p1 test****/" << endl;
c.isPointInnerCircle(p1);
cout << "\n/*****p2 test****/" << endl;
c.isPointInnerCircle(p2);
cout << "\n/*****p3 test****/" << endl;
c.isPointInnerCircle(p3);
}
int main(void)
{
test01();
return 0;
}
对于模板分文件编写。
不能像一般文件分文件编写那样,类的声明和实现要放在同一个文件里。然后main文件包含这个头文件。
错误代码
main.cpp
#include"person.h"
void test01() {
Person<string, int> p("赵云", 38);
p.showPerson();
}
int main() {
test01();
return 0;
}
person.h
#pragma once
#include<iostream>
#include<string>
using namespace std;
template<class T1, class T2>
class Person {
private:
T1 m_Name;
T2 m_Age;
public:
Person(T1 name, T2 age);
void showPerson();
};
person.cpp
#include"person.h"
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {
m_Name = name;
m_Age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
cout << "姓名:" << this->m_Name
<< ", 年龄:" << this->m_Age << endl;
}
运行上面的代码,就会出现链接错误。
类模板会发生两次编译,第一次编译发生在调用模板之前,只会检查语法错误。第二次编译发生在实例化对象之后,编译器会将对象的类型替换掉模板中的未知类型 T,但编译器无法查看到person.cpp中的函数实现代码,因为没有包含该文件。
推荐解决方法:
把声明和具体实现都写在头文件里,并且把头文件后缀写为hpp。在main函数所在文件里包含hpp文件。
即
person.hpp
#pragma once
#include<iostream>
#include<string>
using namespace std;
template<class T1, class T2>
class Person {
private:
T1 m_Name;
T2 m_Age;
public:
Person(T1 name, T2 age); //声明
void showPerson();
};
//类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {
m_Name = name;
m_Age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
cout << "姓名:" << this->m_Name
<< ", 年龄:" << this->m_Age << endl;
}