C++类定义和实现分离的问题

时间:2022-08-30 00:23:33
在C++中,通常要求把类的定义放在一个头文件中,而把类的实现放在一个.cpp的文件中,现在我想问的是,这样做的话,怎样在第三个文件中使用这个类呢?例如在a.h中定义了类a,在a.cpp中实现了它,在test.cpp中我想用这个类,是应该包含a.cpp还是包含a.h。我看到好多书上说吧定义和实现分开,在软件分发的时候,可以直接方法二进制文件,用户使用你写的库的时候只要包含头文件就可以了,但是为什么我写的时候只包含头文件,编译不成功呢?

42 个解决方案

#1


当前是包含头文件了。
把你的错误信息帖出来。

#2


包含a.h

#3


包含头文件a.h就可以了。你的问题看起来是cpp实现的问题吧

#4


我用的是jfe and gcc 写的程序,包含a.h的话,提示错误时没有定义a

#5


194): In function `main':
F:/张金国/code/C++/test/test.cpp:7: undefined reference to `A::A()'
F:\张金国\code\C++\test\test.o(.text+0x1ad):F:/张金国/code/C++/test/test.cpp:8: undefined reference to `A::getName()'
F:\张金国\code\C++\test\test.o(.text+0x262):F:/张金国/code/C++/test/test.cpp:9: undefined reference to `A::setName(std::string)'
F:\张金国\code\C++\test\test.o(.text+0x2f0):F:/张金国/code/C++/test/test.cpp:10: undefined reference to `A::getName()'
F:\张金国\code\C++\test\test.o(.text+0x3b4):F:/张金国/code/C++/test/test.cpp:11: undefined reference to `A::~A()'
F:\张金国\code\C++\test\test.o(.text+0x3db):F:/张金国/code/C++/test/test.cpp:11: undefined reference to `A::~A()'
collect2: ld returned 1 exit status
Failure

#6


很多书上也是说只要包含头文件就可以了,但是我有些迷惑,头文件中并没有类的实现的任何细节,编译器如何知道的类实现是在哪个文件中的呢?我试了一下,包含a.cpp程序没问题。包含a.h的话,编译没问题,但是连接不成功。

#7


.h里写定义,.cpp里谢实现,在其他文件中使用类的话,要#include "a.h"

#8



A.cpp在test.cpp所在目录下的source目录下:
#include "../include/A.h"
A::A(){
   name="";
   cout<<"A() be called!"<<endl;
}
A::A(string name){
A::name=name;
cout<<"A(string name) be called!"<<endl;
}
A::~A(){
cout<<"~A() be called!";
}
void A::setName(const string name){
this->name=name;
return A::name;

}
cout<<"setName(const string name) be called!"<<endl;
}
string A::getName(){
cout<<"getName()be called!"<<endl;

#9


gcc编译器需要指定a.h

gcc -o test test.cpp a.h

或者使用Makefile 定义依赖关系

test : test.o
        gcc -o test test.o

test.o : test.cpp a.h
         gcc -c test.o test.cpp a.h

test可执行文件的生成依赖于test.o
而test.o的生成依赖于a.h

#10


include头文件即可

#11


引用 6 楼 javajz 的回复:
很多书上也是说只要包含头文件就可以了,但是我有些迷惑,头文件中并没有类的实现的任何细节,编译器如何知道的类实现是在哪个文件中的呢?我试了一下,包含a.cpp程序没问题。包含a.h的话,编译没问题,但是连接不成功。

看你的描述,好像是实现的时候出错了,如果要实现函数 setName,应该这么写:

void A::setName(const std::string& sName)
{
  m_strName = sName;
}

看一下你是不是少写了一个“A::”。

另外,你直接把你的头文件、源文件都贴出来,大家可以一下子给你定位问题点。

#12


我的目录结构是这样的:
test.cpp
include :
      A.h
source: 
      A.cpp
test.cpp内容为:

#include <iostream>
#include "./include/A.h"
using namespace std;
int main()
{
cout<<"Hello world"<<endl;
A a=A();
cout<<a.getName()<<endl;
a.setName("zhangjinguo");
cout<<a.getName()<<endl;
return 0;
}

A.h内容为:

#include <iostream>
using namespace std;
#ifndef CLASS_A
#define CLASS_A

class A{
string name;
public:
void setName(const string name);
string getName();
A();
A(string name);
~A();
};
#endif

A.cpp内容为:

#include "./include/A.h"
A::A(){
   name="";
   cout<<"A() be called!"<<endl;
}
A::A(string name){
A::name=name;
cout<<"A(string name) be called!"<<endl;
}
A::~A(){
cout<<"~A() be called!";
}
void A::setName(const string name){
this->name=name;
cout<<"setName(const string name) be called!"<<endl;
}
string A::getName(){
cout<<"getName()be called!"<<endl;
return A::name;

}

#13


test.cpp有没有包含A.h???

#14


引用 11 楼 wanggang999 的回复:
引用 6 楼 javajz 的回复:
很多书上也是说只要包含头文件就可以了,但是我有些迷惑,头文件中并没有类的实现的任何细节,编译器如何知道的类实现是在哪个文件中的呢?我试了一下,包含a.cpp程序没问题。包含a.h的话,编译没问题,但是连接不成功。

看你的描述,好像是实现的时候出错了,如果要实现函数 setName,应该这么写:

C/C++ code

void [color=……

这里不对啊,如果我实现错了的话,我包含a.cpp也不该能运行啊。

#15


用户使用你写的库的时候只要包含头文件就可以了,
==================================
这句话不完整,“还需要链接库文件”

#16


引用 15 楼 mymtom 的回复:
用户使用你写的库的时候只要包含头文件就可以了,
==================================
这句话不完整,“还需要链接库文件”

说的是,对于标准库文件,我们用的时候直接包含头文件吧。

#17


应该在a.cpp文件中也要包含a.h

#18


什么IDE?A.cpp的这一行:
#include "./include/A.h"

是不是应该改成:
#include "../include/A.h"


如果是通过命令行进行编译的,有没有向编译器给出A.cpp所在路径?

#19


引用 17 楼 cjackrose 的回复:
应该在a.cpp文件中也要包含a.h

我的a.cpp中包含了a.h了啊。看我贴出来的代码中不是用include "./include/A.h"吗?

#20


引用 19 楼 javajz 的回复:
引用 17 楼 cjackrose 的回复:
应该在a.cpp文件中也要包含a.h

我的a.cpp中包含了a.h了啊。看我贴出来的代码中不是用include "./include/A.h"吗?

写错了,看我在 #18 给出的回复。

#21


引用 18 楼 wanggang999 的回复:
什么IDE?A.cpp的这一行:

C/C++ code
#include "./include/A.h"

是不是应该改成:

C/C++ code
#include "../include/A.h"


如果是通过命令行进行编译的,有没有向编译器给出A.cpp所在路径?

指教的对,我改了一下,但是问题还在。

#22


如果是通过命令行进行编译的,有没有向编译器给出A.cpp所在路径?
就是说,链接器是否知道到什么地方去查找类A的成员函数的实现?

#23


gcc的话,就不要用中文路径,也不要用含空格的路径!

#24


引用 22 楼 wanggang999 的回复:
如果是通过命令行进行编译的,有没有向编译器给出A.cpp所在路径?
就是说,链接器是否知道到什么地方去查找类A的成员函数的实现?

看来这就是问题的原因了,但是如何让编译器知道A.cpp的路径呢?必须建立工程吗?

#25


你用什么编译器?如果是VC这种IDE,只要你把文件加入项目,编译器自然就知道了,
如果是gcc这样的基于make的...我不熟,Loaden肯定知道怎么弄,先说你用的是什么编译器吧。

#26


用的是gcc的windows版本,vc太大了,机器跑不了。而且我也不喜欢IDE,把什么都做好了,我们自己用的是方便了,但是细节是什么,其实不清楚。

#27


不能用VC,你可以用Code::Blocks,我十分推荐这个。

建议先通过通用的方法学会语言本身,至于编译器工作的原理,
后面慢慢弄清楚也来得及,没人因为你了解编译器工作原理给你薪水,
但如果你可以写出来能解决问题的代码却可以拿到工钱。

如果你真的那么有兴趣了解,可以看看:
An Introduction to GCC .pdf
其他人可能给你推荐更合适的书。

#28


引用 27 楼 wanggang999 的回复:
不能用VC,你可以用Code::Blocks,我十分推荐这个。

建议先通过通用的方法学会语言本身,至于编译器工作的原理,
后面慢慢弄清楚也来得及,没人因为你了解编译器工作原理给你薪水,
但如果你可以写出来能解决问题的代码却可以拿到工钱。

如果你真的那么有兴趣了解,可以看看:
An Introduction to GCC .pdf
其他人可能给你推荐更合适的书。

谢了。

#29


include .h文件应该就可以了吧

#30


这会不想看

#31


加上
#program once
保证只会编译一次

#32


当然是在.h文件上加上这句了

#33


引用 32 楼 chjshan55 的回复:
当然是在.h文件上加上这句了

加上之后出现错误:
invalid preprocessing directive #program
这个预处理指令不是标准的预处理指令吧?

#34


  #pragma是非统一的,他要依靠各个编译器生产者,例如,在SUN C++编译器中:

   // 把name和val的起始地址调整为8个字节的倍数

   #progma align 8 (name, val)

   char name[9];

   double val;

   //在程序执行开始,调用函数MyFunction

   #progma init (MyFunction)

   预定义标识符

本篇文章来源于:开发学院 http://edu.codepub.com   原文链接:http://edu.codepub.com/2009/0725/10978.php
这是我查到的资料。

#35


该回复于2010-05-10 14:53:46被版主删除

#36


#include "./include/A.h"

#37


恩,路径要注意
引用 23 楼 loaden 的回复:
gcc的话,就不要用中文路径,也不要用含空格的路径!

#38


引用 17 楼 cjackrose 的回复:
应该在a.cpp文件中也要包含a.h


另外看看是不是重复包含了

#39


这个不是包含头文件的问题,而是在链接时出错,你可能使用了别人的类或DLL,但是没有加入别人的lib文件或者目标文件obj。

#40


怎么感觉你只是编译了test.cpp而没有编译a.cpp,或者你在链接时没有将a.o链接进来,你需要修改编译脚本(如makefile)

#41


如果想简单点儿的话,直接全部写在a.cpp里面,然后用的时候前导声明下就OK了

#42


感谢各位的热情帮助,现在我已经明白问题的原因。这里我总结一下:
首先我是在命令行下进行编译的,在这里我编译了test.cpp,通过;编译A.cpp,通过。但是直接连接test.o的通不过。我本来的意思是如何在源文件中做一些手脚是的,我们编译的之后,之间连接test.o就可以产生可执行文件,但是一开始我自己也不知道自己想要问什么,另一方面也是不知道问题的原因所在。所以讨论了这么许多。当然了,看了大家的回复,收获还是很大了。这个问题的解决方法有两种:一种就是使用make文件,(如果使用IDE的话其实IED帮我们做了类似的工作),文件之间的以来关系。最后产生可执行文件的时候,只执行文件用到了连个文件test.o和A.o。第二种方法就值直接在命令行中使用连接命令,当然连接命令需要两个参数test.o 和A.o.我想之所以我在这里在跟头还是因为IDE用的多了,而对细节不够了解。如果使用Linux的话,使用makefile一定早把这个问题搞清楚了。总之,我们要记住对一个对文件的的程序开发,我们要告诉编译器文件之前的依赖关系。

#1


当前是包含头文件了。
把你的错误信息帖出来。

#2


包含a.h

#3


包含头文件a.h就可以了。你的问题看起来是cpp实现的问题吧

#4


我用的是jfe and gcc 写的程序,包含a.h的话,提示错误时没有定义a

#5


194): In function `main':
F:/张金国/code/C++/test/test.cpp:7: undefined reference to `A::A()'
F:\张金国\code\C++\test\test.o(.text+0x1ad):F:/张金国/code/C++/test/test.cpp:8: undefined reference to `A::getName()'
F:\张金国\code\C++\test\test.o(.text+0x262):F:/张金国/code/C++/test/test.cpp:9: undefined reference to `A::setName(std::string)'
F:\张金国\code\C++\test\test.o(.text+0x2f0):F:/张金国/code/C++/test/test.cpp:10: undefined reference to `A::getName()'
F:\张金国\code\C++\test\test.o(.text+0x3b4):F:/张金国/code/C++/test/test.cpp:11: undefined reference to `A::~A()'
F:\张金国\code\C++\test\test.o(.text+0x3db):F:/张金国/code/C++/test/test.cpp:11: undefined reference to `A::~A()'
collect2: ld returned 1 exit status
Failure

#6


很多书上也是说只要包含头文件就可以了,但是我有些迷惑,头文件中并没有类的实现的任何细节,编译器如何知道的类实现是在哪个文件中的呢?我试了一下,包含a.cpp程序没问题。包含a.h的话,编译没问题,但是连接不成功。

#7


.h里写定义,.cpp里谢实现,在其他文件中使用类的话,要#include "a.h"

#8



A.cpp在test.cpp所在目录下的source目录下:
#include "../include/A.h"
A::A(){
   name="";
   cout<<"A() be called!"<<endl;
}
A::A(string name){
A::name=name;
cout<<"A(string name) be called!"<<endl;
}
A::~A(){
cout<<"~A() be called!";
}
void A::setName(const string name){
this->name=name;
return A::name;

}
cout<<"setName(const string name) be called!"<<endl;
}
string A::getName(){
cout<<"getName()be called!"<<endl;

#9


gcc编译器需要指定a.h

gcc -o test test.cpp a.h

或者使用Makefile 定义依赖关系

test : test.o
        gcc -o test test.o

test.o : test.cpp a.h
         gcc -c test.o test.cpp a.h

test可执行文件的生成依赖于test.o
而test.o的生成依赖于a.h

#10


include头文件即可

#11


引用 6 楼 javajz 的回复:
很多书上也是说只要包含头文件就可以了,但是我有些迷惑,头文件中并没有类的实现的任何细节,编译器如何知道的类实现是在哪个文件中的呢?我试了一下,包含a.cpp程序没问题。包含a.h的话,编译没问题,但是连接不成功。

看你的描述,好像是实现的时候出错了,如果要实现函数 setName,应该这么写:

void A::setName(const std::string& sName)
{
  m_strName = sName;
}

看一下你是不是少写了一个“A::”。

另外,你直接把你的头文件、源文件都贴出来,大家可以一下子给你定位问题点。

#12


我的目录结构是这样的:
test.cpp
include :
      A.h
source: 
      A.cpp
test.cpp内容为:

#include <iostream>
#include "./include/A.h"
using namespace std;
int main()
{
cout<<"Hello world"<<endl;
A a=A();
cout<<a.getName()<<endl;
a.setName("zhangjinguo");
cout<<a.getName()<<endl;
return 0;
}

A.h内容为:

#include <iostream>
using namespace std;
#ifndef CLASS_A
#define CLASS_A

class A{
string name;
public:
void setName(const string name);
string getName();
A();
A(string name);
~A();
};
#endif

A.cpp内容为:

#include "./include/A.h"
A::A(){
   name="";
   cout<<"A() be called!"<<endl;
}
A::A(string name){
A::name=name;
cout<<"A(string name) be called!"<<endl;
}
A::~A(){
cout<<"~A() be called!";
}
void A::setName(const string name){
this->name=name;
cout<<"setName(const string name) be called!"<<endl;
}
string A::getName(){
cout<<"getName()be called!"<<endl;
return A::name;

}

#13


test.cpp有没有包含A.h???

#14


引用 11 楼 wanggang999 的回复:
引用 6 楼 javajz 的回复:
很多书上也是说只要包含头文件就可以了,但是我有些迷惑,头文件中并没有类的实现的任何细节,编译器如何知道的类实现是在哪个文件中的呢?我试了一下,包含a.cpp程序没问题。包含a.h的话,编译没问题,但是连接不成功。

看你的描述,好像是实现的时候出错了,如果要实现函数 setName,应该这么写:

C/C++ code

void [color=……

这里不对啊,如果我实现错了的话,我包含a.cpp也不该能运行啊。

#15


用户使用你写的库的时候只要包含头文件就可以了,
==================================
这句话不完整,“还需要链接库文件”

#16


引用 15 楼 mymtom 的回复:
用户使用你写的库的时候只要包含头文件就可以了,
==================================
这句话不完整,“还需要链接库文件”

说的是,对于标准库文件,我们用的时候直接包含头文件吧。

#17


应该在a.cpp文件中也要包含a.h

#18


什么IDE?A.cpp的这一行:
#include "./include/A.h"

是不是应该改成:
#include "../include/A.h"


如果是通过命令行进行编译的,有没有向编译器给出A.cpp所在路径?

#19


引用 17 楼 cjackrose 的回复:
应该在a.cpp文件中也要包含a.h

我的a.cpp中包含了a.h了啊。看我贴出来的代码中不是用include "./include/A.h"吗?

#20


引用 19 楼 javajz 的回复:
引用 17 楼 cjackrose 的回复:
应该在a.cpp文件中也要包含a.h

我的a.cpp中包含了a.h了啊。看我贴出来的代码中不是用include "./include/A.h"吗?

写错了,看我在 #18 给出的回复。

#21


引用 18 楼 wanggang999 的回复:
什么IDE?A.cpp的这一行:

C/C++ code
#include "./include/A.h"

是不是应该改成:

C/C++ code
#include "../include/A.h"


如果是通过命令行进行编译的,有没有向编译器给出A.cpp所在路径?

指教的对,我改了一下,但是问题还在。

#22


如果是通过命令行进行编译的,有没有向编译器给出A.cpp所在路径?
就是说,链接器是否知道到什么地方去查找类A的成员函数的实现?

#23


gcc的话,就不要用中文路径,也不要用含空格的路径!

#24


引用 22 楼 wanggang999 的回复:
如果是通过命令行进行编译的,有没有向编译器给出A.cpp所在路径?
就是说,链接器是否知道到什么地方去查找类A的成员函数的实现?

看来这就是问题的原因了,但是如何让编译器知道A.cpp的路径呢?必须建立工程吗?

#25


你用什么编译器?如果是VC这种IDE,只要你把文件加入项目,编译器自然就知道了,
如果是gcc这样的基于make的...我不熟,Loaden肯定知道怎么弄,先说你用的是什么编译器吧。

#26


用的是gcc的windows版本,vc太大了,机器跑不了。而且我也不喜欢IDE,把什么都做好了,我们自己用的是方便了,但是细节是什么,其实不清楚。

#27


不能用VC,你可以用Code::Blocks,我十分推荐这个。

建议先通过通用的方法学会语言本身,至于编译器工作的原理,
后面慢慢弄清楚也来得及,没人因为你了解编译器工作原理给你薪水,
但如果你可以写出来能解决问题的代码却可以拿到工钱。

如果你真的那么有兴趣了解,可以看看:
An Introduction to GCC .pdf
其他人可能给你推荐更合适的书。

#28


引用 27 楼 wanggang999 的回复:
不能用VC,你可以用Code::Blocks,我十分推荐这个。

建议先通过通用的方法学会语言本身,至于编译器工作的原理,
后面慢慢弄清楚也来得及,没人因为你了解编译器工作原理给你薪水,
但如果你可以写出来能解决问题的代码却可以拿到工钱。

如果你真的那么有兴趣了解,可以看看:
An Introduction to GCC .pdf
其他人可能给你推荐更合适的书。

谢了。

#29


include .h文件应该就可以了吧

#30


这会不想看

#31


加上
#program once
保证只会编译一次

#32


当然是在.h文件上加上这句了

#33


引用 32 楼 chjshan55 的回复:
当然是在.h文件上加上这句了

加上之后出现错误:
invalid preprocessing directive #program
这个预处理指令不是标准的预处理指令吧?

#34


  #pragma是非统一的,他要依靠各个编译器生产者,例如,在SUN C++编译器中:

   // 把name和val的起始地址调整为8个字节的倍数

   #progma align 8 (name, val)

   char name[9];

   double val;

   //在程序执行开始,调用函数MyFunction

   #progma init (MyFunction)

   预定义标识符

本篇文章来源于:开发学院 http://edu.codepub.com   原文链接:http://edu.codepub.com/2009/0725/10978.php
这是我查到的资料。

#35


该回复于2010-05-10 14:53:46被版主删除

#36


#include "./include/A.h"

#37


恩,路径要注意
引用 23 楼 loaden 的回复:
gcc的话,就不要用中文路径,也不要用含空格的路径!

#38


引用 17 楼 cjackrose 的回复:
应该在a.cpp文件中也要包含a.h


另外看看是不是重复包含了

#39


这个不是包含头文件的问题,而是在链接时出错,你可能使用了别人的类或DLL,但是没有加入别人的lib文件或者目标文件obj。

#40


怎么感觉你只是编译了test.cpp而没有编译a.cpp,或者你在链接时没有将a.o链接进来,你需要修改编译脚本(如makefile)

#41


如果想简单点儿的话,直接全部写在a.cpp里面,然后用的时候前导声明下就OK了

#42


感谢各位的热情帮助,现在我已经明白问题的原因。这里我总结一下:
首先我是在命令行下进行编译的,在这里我编译了test.cpp,通过;编译A.cpp,通过。但是直接连接test.o的通不过。我本来的意思是如何在源文件中做一些手脚是的,我们编译的之后,之间连接test.o就可以产生可执行文件,但是一开始我自己也不知道自己想要问什么,另一方面也是不知道问题的原因所在。所以讨论了这么许多。当然了,看了大家的回复,收获还是很大了。这个问题的解决方法有两种:一种就是使用make文件,(如果使用IDE的话其实IED帮我们做了类似的工作),文件之间的以来关系。最后产生可执行文件的时候,只执行文件用到了连个文件test.o和A.o。第二种方法就值直接在命令行中使用连接命令,当然连接命令需要两个参数test.o 和A.o.我想之所以我在这里在跟头还是因为IDE用的多了,而对细节不够了解。如果使用Linux的话,使用makefile一定早把这个问题搞清楚了。总之,我们要记住对一个对文件的的程序开发,我们要告诉编译器文件之前的依赖关系。