为啥一个函数在一个文件中声明几次都可以?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为啥一个函数在一个文件中声明几次都可以?相关的知识,希望对你有一定的参考价值。

如题

声明只是告诉后面的代码:你应该这样调用这相函数,参数是什么,返回值是什么,所以你多告诉几次也没事只要不让编译器困惑就行。
声明并没有告诉后面的代码这个函数是拿传进去参数做什么,返回值是什么意思,这些是函数的具体实现细节,必须只有一份。
参考技术A 1Z时正确的,应为声明只表示这里可以调用相应的方法了,你告诉好几次也不会有什么关系。多次和一次的效果是一样的。

2Z指的不是声明,指的是函数的重构,和声明没关系。
参考技术B C、VB语言不可以,C++、Java、C#等面向对象的语言可以,叫重构:
int a()

int a(int c)

int a(float c)

这样是可以的,调用的时候系统会根据形参的不同调用不同的函数,比如:
a();
这就调用了第一个。
a(3); //形参为int
这就调用了第二个。
a(3.22); //形参为float
这就调用了第三个。
参考技术C 只有在极少数内存优化的情况下才会这么用,应该严格避免使用这种定义方法,命名要有意义且尽是唯一,函数用完及时析构

为啥模板类函数必须在同一个翻译单元中声明?

【中文标题】为啥模板类函数必须在同一个翻译单元中声明?【英文标题】:Why do template class functions have to be declared in the same translation unit?为什么模板类函数必须在同一个翻译单元中声明? 【发布时间】:2011-11-05 23:12:00 【问题描述】:

以这段代码为例:

/*
 * foo.h
 *
 *  Created on: Nov 5, 2011
 *      Author: AutoBotAM
 */

#ifndef FOO_H_
#define FOO_H_

template<typename Type>
class Foo

public:
    void Bar(Type object);
;


#endif /* FOO_H_ */

.

/*
 * foo.cpp
 *
 *  Created on: Nov 5, 2011
 *      Author: AutoBotAM
 */

#include <iostream>
using namespace std;

#include "foo.h"

template<typename Type>
void Foo<Type>::Bar(Type object)

    cout << object;

.

/*
 * main.cpp
 *
 *  Created on: Oct 15, 2011
 *      Author: AutoBotAM
 */

#include <iostream>
using namespace std;

#include "foo.h"

Foo<int> foo;

int main()

    cout << "The year is ";
    foo.Bar(2011);
    return 0;

这就是我通常声明非模板类的方式。不幸的是,此代码导致错误../src/main.cpp:18: undefined reference to 'Foo&lt;int&gt;::Bar(int)'(在 MinGW 中)。我做了一些阅读,结果你必须在同一个翻译单元中声明模板类,如下所示:

/*
 * foo.h
 *
 *  Created on: Nov 5, 2011
 *      Author: AutoBotAM
 */

#ifndef FOO_H_
#define FOO_H_

template<typename Type>
class Foo

public:
    void Bar(Type object)
    
        cout << object;
    
;


#endif /* FOO_H_ */

我最大的问题是,你为什么要这样做?我可以想象这个方案在开发过程中会遇到一些陷阱。例如,假设我们有 50 个翻译单元#包括 foo.h,我们将更改为 void Foo::Bar(Type)。由于Bar 位于头文件中,因此我们必须等待所有 50 个翻译单元编译完成才能得到任何结果。如果我们让Bar 单独在foo.cpp 工作,我们只需要等待1 个翻译单元编译。有什么办法可以解决这个问题吗?

感谢您的建议!

【问题讨论】:

【参考方案1】:

模板位于编译和链接时间之间。在看到模板声明后,Eager 实现可以做很多事情,但在模板使用其模板参数实例化之前无法生成实际代码。

可以在 cpp 文件中拥有模板类函数,并且您可以使用将要使用的参数显式实例化它。但是,您只能在整个程序中使用这些实例。例如,您可以添加到 foo.cpp

template class Foo<int>;

现在您可以在任何地方使用Foo&lt;int&gt;s,即使实现是在它自己的翻译单元中。但是,您不能使用任何其他类型的 Foo&lt;&gt;,因为链接器将无法找到它的函数(它们实际上并不存在)。

【讨论】:

“您可以在 cpp 文件中包含模板类函数,并且您可以使用您将要使用的参数显式实例化它。” 这个语法是什么? (编辑,没关系,谢谢)【参考方案2】:

模板不是类型。它们只是模板。它们只有在被实例化(具有完整的参数集)时才成为类型。

编译要求所有必要的type 定义在编译时可用。此外,链接要求所有必要的函数定义,包括成员函数,都存在于某个翻译单元中(内联提供了对单一定义规则的通常豁免)。

如果将所有这些放在一起,几乎会自动得出一个模板类的所有模板成员函数定义必须可用于编译过程中每个使用的模板实例在某个时间点

另一方面,请考虑以下设置:

// Header file:
template <typename T> struct Foo  void f(); 

// "Implementation" file
template <typename T> void Foo::f()  /* stuff */ 

如果编译实现文件,它不包含任何代码,因为没有要编译的模板实例。头文件的用户可能会实例化Foo&lt;int&gt;,但类的主体永远不会在任何 TU 中实例化,因此在拼凑程序时会出现链接器错误。

将模板视为代码生成工具而不是实际代码可能会有所帮助,至少出于编译的目的。

【讨论】:

【参考方案3】:

模板为meta programming。它们不会(直接)编译成目标代码。只是他们的结果。

【讨论】:

从来不知道这个。虽然我仍然想知道为什么它们必须在同一个翻译单元中声明。 同样的原因,你不能在一个文件中声明半个类,而在另一个文件中声明另一半类。将模板视为仅声明,编译器正在编写您的实现。 可能听起来很俗气,但您可以将模板视为“类固醇上的宏”。与宏不同,它们深度集成到核心语言中。但是就像宏模板在被编译器实例化之前实际上不会发出代码。 @seand 同意。我用的不多,但一直认为它们是带有类型检查的#define。 @Joe 我认为模板非常强大——只要它们没有被滥用和过度使用。我无法理解每隔一行都是模板的 C++ 代码:(【参考方案4】:

大多数编译器还不支持外部模板,这将允许您正在寻找的 cpp/h 类型分开。但是,您仍然可以将模板声明与类似于您想要的实现分开。将声明放在 .h 文件中,将实现放在单独的源文件中,使用您想要的任何扩展名(.i 和 .ipp 很流行),然后将 #include 源文件放在 .h 文件的底部。编译器看到一个翻译单元,然后你就得到了代码分离。

/*
* foo.h
*
* Created on: Nov 5, 2011
* Author: AutoBotAM
*/
#ifndef FOO_H_
#define FOO_H_

template<typename Type>
class Foo

public:
    void Bar(Type object);
;

#include "foo.ipp"

#endif /* FOO_H_ */

.

/*
* foo.ipp
*
* Created on: Nov 5, 2011
* Author: AutoBotAM
*/

#include <iostream>

template<typename Type>
void Foo<Type>::Bar(Type object)

    std::cout << object;

【讨论】:

以上是关于为啥一个函数在一个文件中声明几次都可以?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我这边2个天融信的防火墙HA做主备模式的话,多切换几次都会变成主墙?

为啥另一个函数中的函数声明会编译,它有啥作用?

为啥一个成员函数只存在一次,甚至在一个包含多个的 .h 文件中定义? [复制]

为啥我可以在 C 中调用一个函数而不声明它,但在 C++ 中却不能?

为啥我的 Javascript 函数只能工作几次?

微信小程序怎么写代码,试了几次都是错误,不会写,不知道怎么添加代