C/C++:多个.cpp文件包括同一个.h头文件定义方法
本文解决multiple definition of `XX'的错误。【出于反爬虫的目的,你不是在http://blog.csdn.net/zhanh1218上看到的,肯定不是最新最全的。】
关于头文件的定义中,请一定加上下面代码(此为头文件保护符):
<span style="font-size:14px;"><span style="font-size:12px;">#ifndef PERSON_H_ #define PERSON_H_ // 你的代码块 #endif /* PERSON_H_ */</span></span>当中PERSON_H_为保护符的名字,一般建议与类名保持一致!样例中我的类名为Person.h。
每当编译器遇到#include时,都要去编译相关代码块,可是编译器不知道是不是已经编译过了,假设编译过了还去编译,那是不是等于代码块写了两次呢?所以,须要有不反复编译的机制,而这个机制正式以上代码。
详细实现为:#ifdef当且仅当变量已定义时为真,#ifndef当且仅当变量没有定义时为真。一旦检測结果为真,则运行兴许操作直至遇到#endif。
也就是说:假设首次include "Person.h",PERSON_H_是未定义,此时,编译器会define这个保护符,并运行代码块的编译!直到遇到#endif。下次遇到这个保护符,就不会运行代码块的编译了。这种机制保证了不会反复编译。
实际使用中,我发现,单个cpp文件里多次include 同一个.h头文件或者头文件里多次include某个头文件,不会有问题。可是,多个cpp文件都include 同一个.h头文件时,这样会出问题。问题是类外定义的非static及非inline函数还是会报multiple definition of `XX'的错误。【也就是说:#define的作用域仅仅是单个.cpp,而不是全局全部的.cpp文件】
终于解决方法是:仅仅在头文件定义类的申明和类的主体定义(也就是{}内的内容),在一个同名的.cpp文件中定义类外函数的实现!问题完美解决。所以,就算是大神写的书,书上也不全然是对的,或者表述的所有都清楚。
那么为什么头文件能够定义成下面形式呢?而不是仅仅申明,不定义类体呢?
<span style="font-size:14px;"><span style="font-size:12px;">class A { // 类定义 };</span></span>
类的定义,仅仅是告诉编译器,类的数据格式是怎样的,实例话后对象该占多大空间。 类的定义也不产生目标代码。因此它和普通变量的声明唯一的差别是不能在同一编译单元内出现多次。
还有一个原因就是,类能够在多个.cpp文件中重定义,变量却不行,除非用extern或者staic修饰的变量。
至于普通变量:同意static型的变量的定义;同意extern申明(不能定义!);直接申明比如int a; 是不行的,也是多次又一次定义。
extern表明该变量在别的地方已经定义过了,在这里要使用那个变量;static 表示静态的变量,分配内存的时候,存储在静态区,不存储在栈上面。【一篇不错的Blog:点击打开链接】
以下是代码演示样例,此实例部分为C++ Primer练习题。【反爬虫,第二天更新代码!】
/********************************************************************* * file_name: vector_test.cpp * * Created on: 2014年6月28日 下午3:34:23 * Author: The_Third_Wave, Blog: http://blog.csdn.net/zhanh1218 * Email: zhanh121823@sina.com * Last modified: 2014年6月28日 下午3:34:23 *********************************************************************/ #include <iostream> #include <vector> #include <string> #include "Headers/Person.h" extern int k; int main() { std::vector<Person> per = {{"The_Third_Wave", 100, "Blog: http://blog.csdn.net/zhanh1218"}}; // 类初始化+vector初始化,所以{{}, {}}必须的 for (auto &p: per) { print(std::cout, p); } }
/********************************************************************* * file_name: ddqdq.cpp * * Created on: 2014年6月28日 下午10:28:42 * Author: The_Third_Wave, Blog: http://blog.csdn.net/zhanh1218 * Email: zhanh121823@sina.com * Last modified: 2014年6月28日 下午10:28:42 *********************************************************************/ #include <iostream> #include <vector> #include "Headers/Person.h" extern int k;
/********************************************************************* * file_name: Person.h * * Created on: 2014年6月28日 下午11:47:08 * Author: The_Third_Wave, Blog: http://blog.csdn.net/zhanh1218 * Email: zhanh121823@sina.com * Last modified: 2014年6月28日 下午11:47:08 *********************************************************************/ #ifndef PERSON_H_ #define PERSON_H_ /*****************************BEGIN***********************************/ #include <iostream> #include <string> using namespace std; extern int a; class Person { friend istream &read(istream &is, Person &item); friend ostream &print(ostream &os, const Person &item); public: Person() = default; Person(const string &n, unsigned int a, string add): name(n), age(a), address(add) { } Person(istream &); string Name() const {return name;} unsigned int Age() const {return age;} string Address() const {return address;} private: string name = ""; unsigned int age = 1; string address = ""; }; inline Person::Person(istream &is) { read(is, *this); } /******************************END************************************/ #endif /* PERSON_H_ */
/********************************************************************* * file_name: Person.cpp * * Created on: 2014年6月28日 下午10:55:32 * Author: The_Third_Wave, Blog: http://blog.csdn.net/zhanh1218 * Email: zhanh121823@sina.com * Last modified: 2014年6月28日 下午10:55:32 *********************************************************************/ #include <iostream> #include <string> #include "Person.h" using namespace std; istream &read(istream &is, Person &item) { is >> item.name >> item.age >> item.address; return is; } ostream &print(ostream &os, const Person &item) { os << item.name << " " << item.age << " " << item.address << endl; return os; }
还有不懂的请留言。
本文由@The_Third_Wave(Blog地址:http://blog.csdn.net/zhanh1218)原创。还有未涉及的,会不定期更新,有错误请指正。
假设你看到这篇博文时发现不完整,那是我为防止爬虫先公布一半的原因,请看原作者Blog。
假设这篇博文对您有帮助,为了好的网络环境,不建议转载,建议收藏!假设您一定要转载,请带上后缀和本文地址。