关于全局函数的声明和定义的问题

FrankSun80 2009-12-29 09:13:43
我在一个common.h文件中定义了一个全局函数
void ArraySet(double *pArr, int len, double initValue)
{
return;
}

然后工程中有两个文件分别包含了(直接或间接)这个头文件。就会出现重定义的错误:
1>Linking...
1>BB.obj : error LNK2005: "void __cdecl ArraySet(double *,int,double)" (?ArraySet@@YAXPANHN@Z) already defined in AA.obj

请问这是为什么?

该如何解决这个问题,如果我就是想定义这么一个全局函数,该怎么办?

现有的解决方法:
1. 将实现移到cpp文件中去
2. 改为static函数
3. 将该函数包装到类里去,并作为类的static函数

请问哪个方法最好?

...全文
1535 33 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
FrankSun80 2009-12-29
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 paulpeath 的回复:]
Frank:
    方法3将函数作为类的静态对象,在使用时要直接引用类作用符::,即在不同的函数体内,引入类对象。
    使用namespace 的原意是,将与此函数有关的文件放入同一namespace下,这样,各个文件都可使用。
    不知,我对namespace理解是否有误,请大家指正。
[/Quote]

谢谢你的回答!
用方法3可以解决问题,但是用namespace好像不能解决这个问题。(如下:声明和定义仍然都在.h文件中)

#pragma once

#ifndef FMCommonDefine_h__
#define FMCommonDefine_h__
namespace XX
{
void ArraySet(double *pArr, int len, double initValue)
{
}
}

#endif // FMCommonDefine_h__

我的理解是不是,方法3和方法2本质上是一样的。

另外,项目里最近用了很多模板,在模板中实现和定义都只能在头文件中,所以在头文件中会有很多实现,很多类甚至没有cpp文件了。所以才想要把这个问题弄清楚。
arong1234 2009-12-29
  • 打赏
  • 举报
回复
其实看看8F的链接,我记得里面把出现问题的原理都说了
arong1234 2009-12-29
  • 打赏
  • 举报
回复
首先你要明白你的问题的实质是“实体重定义”,也就是在不同的编译单元里,同样的实体被再次生成了。方法3实际上把一个函数隐藏进类里,类本身只是类型,它不会生成实体,所以不会有问题。实体只是指变量和函数体。

如果用下面方法来应用方法3,你就会发现一样是失败的:因为类外定义的函数体导致了实体重定义

class MyClass
{
void foo(); //注意:是否是static和这个问题其实无关
};

void MyClass::foo()
{
}




[Quote=引用 18 楼 sunyeyi 的回复:]
引用 7 楼 paulpeath 的回复:

    不过好像namespace不能解决,既然方法2会造成函数体重复,那么方法3为什么能解决呢?是不是真的该用类来解决一切了呀:)
[/Quote]
arong1234 2009-12-29
  • 打赏
  • 举报
回复
你理解当然有误!namespace只用于解决同名函数冲突问题,对于他这种实体重定义错误一点用都不可能有
pragma once和前面说的guard macro的作用是一样的,这只是微软的一个私有的扩展。他第一不能解决此问题,第二如果你用同样的代码再其他编译器里,实际上会有编译错误,不是所有编译器都认识这个的(实在不知道上面那位声称王道的是怎么认为他是王道的)

[Quote=引用 20 楼 paulpeath 的回复:]
Frank:
    方法3将函数作为类的静态对象,在使用时要直接引用类作用符::,即在不同的函数体内,引入类对象。
    使用namespace 的原意是,将与此函数有关的文件放入同一namespace下,这样,各个文件都可使用。
    不知,我对namespace理解是否有误,请大家指正。
[/Quote]
hacker1125 2009-12-29
  • 打赏
  • 举报
回复
建议用1。

按规范,实现最好写在cpp,不要放在h
paulpeath 2009-12-29
  • 打赏
  • 举报
回复
Frank:
方法3将函数作为类的静态对象,在使用时要直接引用类作用符::,即在不同的函数体内,引入类对象。
使用namespace 的原意是,将与此函数有关的文件放入同一namespace下,这样,各个文件都可使用。
不知,我对namespace理解是否有误,请大家指正。
  • 打赏
  • 举报
回复
包含一次头文件即可啊。
FrankSun80 2009-12-29
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 paulpeath 的回复:]
Frank:
  方法1:在一个CPP文件定义,其他文件含有函数声明;既可编译使用;
  方法2:改为static函数 。不好,这样每个CPP都要有同样static函数,这样的方法很愚蠢,但确实可以使用。
  方法3:比方法2好点,若函数与类关系不大有点牵强;
  建议:通过namespace来解决。

[/Quote]

谢谢您的建议:
不过好像namespace不能解决,既然方法2会造成函数体重复,那么方法3为什么能解决呢?是不是真的该用类来解决一切了呀:)

另外:
#pragma once
#ifndef FMCommonDefine_h__
都使用了,好像与本问题无关。

呵呵,早上一直在开会,还没来得及看大家的回复,先谢谢大家了
等下再来~
howlet2 2009-12-29
  • 打赏
  • 举报
回复
除了上一点还不够,把这个函数移动到.cpp里
.h里加一个extern void ArraySet(double *pArr, int len, double initValue) ;
定义全局变量也类似
howlet2 2009-12-29
  • 打赏
  • 举报
回复
#pragma once是王道
arong1234 2009-12-29
  • 打赏
  • 举报
回复
呵呵,最好自己试试看行不行
[Quote=引用 14 楼 huangjn213 的回复:]
好像在头文件的开头加一个#pragma once就行    !!
[/Quote]
huangjn213 2009-12-29
  • 打赏
  • 举报
回复
好像在头文件的开头加一个#pragma once就行 !!
pur_e 2009-12-29
  • 打赏
  • 举报
回复
头文件的原理是:将include的文件内用原样copy过来~

基础不牢,
pur_e 2009-12-29
  • 打赏
  • 举报
回复
Quote=引用 10 楼 arong1234 的回复:]
即使加上你那个宏,也不能在头文件中定义int
引用 6 楼 pur_e 的回复:
额,当然,方法的实现应该放在cpp文件中的,但如果是int a;呢,也会报错重复定义的,头文件需要避免重复定义

[/Quote]

刚测试过了,受教了
[
das_jack 2009-12-29
  • 打赏
  • 举报
回复
一般地,函数声明与实现是分离的
简单函数的声明及实现可以放在头文件里,使用inline,关于何种情况不能使用inline,请自行查找
arong1234 2009-12-29
  • 打赏
  • 举报
回复
即使加上你那个宏,也不能在头文件中定义int
[Quote=引用 6 楼 pur_e 的回复:]
额,当然,方法的实现应该放在cpp文件中的,但如果是int a;呢,也会报错重复定义的,头文件需要避免重复定义
[/Quote]
arong1234 2009-12-29
  • 打赏
  • 举报
回复
namespace怎么解决?namespace对此毫无作用
[Quote=引用 7 楼 paulpeath 的回复:]
Frank:
  方法1:在一个CPP文件定义,其他文件含有函数声明;既可编译使用;
  方法2:改为static函数 。不好,这样每个CPP都要有同样static函数,这样的方法很愚蠢,但确实可以使用。
  方法3:比方法2好点,若函数与类关系不大有点牵强;
  建议:通过namespace来解决。

[/Quote]
arong1234 2009-12-29
  • 打赏
  • 举报
回复
这不是重复引用!你这种方法只适用于同一个头文件在同一个cpp中被包含的问题,不能解决被多个cpp文件中被包含的问题。你应该看看
http://blog.vckbase.com/arong/archive/2004/05/28/294.aspx
[Quote=引用 2 楼 pur_e 的回复:]
都不好,你这是头文件重复引用了,应该在头尾加上:

C/C++ code
#ifndef _COMMON_H_#define//头文件内容#endif
[/Quote]
paulpeath 2009-12-29
  • 打赏
  • 举报
回复
Frank:
方法1:在一个CPP文件定义,其他文件含有函数声明;既可编译使用;
方法2:改为static函数 。不好,这样每个CPP都要有同样static函数,这样的方法很愚蠢,但确实可以使用。
方法3:比方法2好点,若函数与类关系不大有点牵强;
建议:通过namespace来解决。
pur_e 2009-12-29
  • 打赏
  • 举报
回复
额,当然,方法的实现应该放在cpp文件中的,但如果是int a;呢,也会报错重复定义的,头文件需要避免重复定义
加载更多回复(13)

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧