面试的时候遇到2次关于这个关键字的作用了,今天就来让我们来详细的了解一下吧.
case 1: 在一个h文件中使用extern修饰变量或者函数(注意被extern修饰的变量或者函数不能提供定义或者初始值)表明共享该变量或者函数等,所谓共享也就是说如果extern修饰的变量在 one.cpp中被修改,那么在two.cpp中访问到的是修改后的值(前提是one.cpp和two.cpp都include了该h文件).另外特别需要注意的是被extern修饰的变量或者函数只能被定义一次,也就是说可以在任何包含该h文件的cpp文件中被定义一次!
//head.h
extern int y;
extern void printU();
//One.cpp
#include "head.h"
#include <iostream>
int y = 10; //注意我们提供了一次定义.
void printU()
{
std::cout<< "U" << std::endl;
}
//Two.cpp
#include "head.h"
y = 20;
//main.cpp
#include "head.h"
#include <iostream>
int main()
{
//先运行One.cpp中的内容再运行Two.cpp的内容
std::cout<< y << std::endl; //输出: 20;
printU();
return 0;
}
case 2: 声明函数的编译和链接方式
语法:
extern string-literal { declaration-seq(optional) }
extern string-literal declaration
Demo1:
//head.h
extern void printT(int x); //注意C也是支持的
extern int number;
//CSource.c
#include <stdio.h>
#include "head.h"
void printT(int x)
{
number + 1;
printf("%d", x);
}
//source.cpp
#include <iostream>
#ifdef __cplusplus //双下划线.
extern "C"
{
#endif __cplusplus
#include "head.h"
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
int number; //注意这里提供了默认初始化.
//extern "C" int number; 这种情况是不提供默认初始化的相当于: extern "C" { extern int number;}
#ifdef __cplusplus
}
#endif __cplusplus
int main()
{
printT(20);
std::cout << number << std::endl;
return 0;
}
case 3: extern template
在C++98/03语言标准中,对于源代码中出现的每一处模板实例化,编译器都需要去做实例化的工作;而在链接时,链接器还需要移除重复的实例化代码。显然,让编译器每次都去进行重复的实例化工作显然是不必要的,并且连接器也因此受累。
在现实编码世界里,一个软件的实现可能会在很多代码块中使用同一种类型去实例化同一个模板。此时,如果能够让编译器避免此类重复的实例化工作,那么可以大大提供编译器的工作效率。因此,人们迫切需要一种手段(一种声明方式)来告诉编译器“该处出现的模板实例化工作已在其它编译单元中完成,不再需要进行实例化”。
于是,一个新的语言特性—外部模板(Extern Template)—被纳入到C++0x标准中。
在C++98/03中,已经有一个叫做显示实例化(Explicit Instantiation)的语言特性,其目的是指示编译器立即进行模板实例化操作(即强制实例化)。而外部模板语法就是在显示实例化指令的语法基础上进行修改得到的:通过在显示实例化指令前添加前缀extern,从而得到外部模板的语法。
Demo1: 针对函数的情况
语法:
extern template return-type name < argument-list > ( parameter-list ) ;
extern template return-type name ( parameter-list ) ;
//head.h
#include <iostream>
extern int number;
//int num; //error!!!!!!!!
void function();
inline void functionInl()
{
std::cout << "inline function" << std::endl;
}
inline namespace TT {
inline void functionNpc()
{
std::cout << "namespace inline function!" << std::endl;
}
}
template<typename Ty>
void functionTem(Ty val)
{
std::cout << val << std::endl;
}
void functionUseTem();
//test1.cpp
#include "head.h"
template void functionTem<int>(int val);
void function()
{
functionTem<int>(20);
}
int number = 20;
//test2.cpp
#include "head.h"
extern template void functionTem<int>(int val);
void functionUseTem()
{
functionTem<int>(20);
}
//main.cpp
#include <iostream>
#include "head.h"
int main()
{
std::cout << number << std::endl;
function();
functionInl();
functionTem(20);
functionNpc();
functionUseTem();
return 0;
}
Demo2: 针对class的情况
//head.h
#include <iostream>
#include <typeinfo>
extern void invoke()noexcept;
extern void invoke2();
template<typename T>
class Test1
{
public:
void print()const
{
std::cout << "test1 with type: " << typeid(T).name() << std::endl;
}
};
template<>
void Test1<std::string>::print()const
{
std::cout << "shihuamarryme" << std::endl;
}
class Test2
{
public:
template<typename T>
inline void print(T&& value)const noexcept
{
std::cout << value << std::endl;
}
};
//source1.cpp
#include "head.h"
//case 1:
template class Test1<int>;
//case 2:
template void Test1<double>::print()const;
template void Test1<std::string>::print()const;
//case 3:
template void Test2::print<int>(int&& value)const noexcept;
void invoke() noexcept
{
Test1<int> test;
test.print();
Test1<double> test2;
test2.print();
Test1<std::string> test3;
test3.print();
Test2 test4;
test4.print(4);
}
//source2.cpp
#include "head.h"
//case 1: 针对整个class的情况
extern template class Test1<int>;
//case 2: 针对成员函数的情况
extern template void Test1<std::string>::print()const;
extern template void Test1<double>::print()const;
//case 3:
extern template void Test2::print<int>(int&& value)const noexcept;
void invoke2()
{
Test1<int>{}.print();
Test1<double>{}.print();
Test1<std::string>{}.print();
Test2{}.print(4);
}
//main.cpp
#include "head.h"
int main()
{
invoke();
invoke2();
return 0;
}