Parsing inner and outer connections in C++

 

Before talking about internal connections and external connections, let’s first explain some concepts. 

  1. Declaration

  A declaration introduces a name into a scope;

  in C++, it is legal to repeat a declaration in a scope. 
The following are declarations: 

int foo(int,int); //function forward declaration 

typedef int Int; //typedef declaration 

class bar; //class forward declaration 

extern int g_
var ; //external reference declaration 

class bar; //class forward declaration 

typedef int Int; //typedef declaration 

extern int g_var; //external reference declaration 

friend test
; //friend declaration 

using std::cout; //namespace reference declaration

  You can repeat these declarations multiple times in the same scope. 

  There are two types of declarations that cannot be repeated, that is, the declaration of class member functions and static data members.

class foo 

 typedef static
 int i; 
 typedef static int i;//不可以 
 public: 
  int foo(); 
  int foo();//不可以 
};

2 .定义

  一个定义提供一个实体(类型、实例、函数)在一个作用域的唯一描述。

  在同一作用域中不可重复定义一个实体。

  以下都是定义。

int y;

class foo {...};

struct bar {...};

foo* p;

static int i;

enum Color{RED,GREEN,BLUE};

const double PI = 3.1415;

union Rep{...};

void test(int p) {};

foo a;

bar b;

3.编译单元

  当一个c或cpp文件在编译时,预处理器首先递归包含头文件,形成一个含有所有 必要信息的单个源文件,这个源文件 就是一个编译单元。这个编译单元会被编译成为一个与cpp文件名同名的目标文件(.o或是.obj)。连接程序把不同编译单元中产生的符号联系起 来,构成一个可执行程序。

4.自由函数

  如果一个函数是自由函数,那么这个函数不是类的成员函数,也不是友元函数。

       下面来看内部连接和外部连接
  内部连接:如果一个名称对于它的编译单元来说是局部的,并 且在连接时不会与其它编译单元中的同样的名称相冲突,那么这个名称有内部连接(注:有时也将声明看作是无连接的,这里我们统一看成是内 部连接的)。

  以下情况有内部连接:
  a)所有的声明

  b)名字空间(包括全局名字空间)中的静 态自由函数、静态友元函数、静态变量的定义

  c)enum定义

  d)inline函数定义(包括自由函数和非自由函数) 

  e)类的定义

  f)名字空间中const常量定义

  g)union的定义

  外部连接:在一 个多文件程序中,如果一个名称在连接时可以和其它编译单元交互,那么这个名称就有外部连接。

  以下情况有外部连接:

  a)类非inline函数总有外部连接。包括类成员函数和类静态成员函数

  b)类静态成员变量总有外部连接。

  c)名字空间(包括全局名字空间)中非静态自由函数、非静态友元函数及非静态变量

  下面举例说明:

  a)声明、enum定义、union定义有内部连接

  所有的声明、enum定义及union定义在编译后不会产生连接符号,也就是在 不同编译单元中有相同名称的声明及enum、union定义并不会在连接时发生发现多个符号的错误。

// main.cpp

typedef int Int; //typedef 声明,内部连接 

enum Color{red}; //enum定义,内部连接

union X //union定义,内部连接
{
 long a;
 char b[10];
};

int main(void)
{
Int i = red;
return i;
}

// a.cpp

typedef int Int; //在a.cpp中重声明一个int类型别名,在连接时不会发生错误
enum Color{blue}; //在a.cpp中重定义了一个enum Color,在连接时不会发生错误
const Int i =blue; //const常量定义,内部连接
union X //union定义,内部连接
{
 long a;
 char b[10];
};


  b)名字空间中静态自由函数、静态 友元函数、静态变量、const常量定义有内部连接

// main.cpp

namespace test
{
 int foo(); //函数声明,内部连接 
 static int i = 0; //名字空间静态变量定义,内部连接
 static int foo() { return 0;} //名字空间静态函数定义,内部 连接
}

static int i = 0; //全局静态变量定义,内部连接
static int foo() {return 1;} //全局静态函数定义, 内部连接
const int k = 0; //全局const常量定义,内部连接
int main(void)
{
 return 0;
}

//a.cpp

namespace test
{
 int i = 0; //名字空间变量定义,外部连接
 int foo() {return 0;} //名字 空间函数定义,外部连接
}

int i = 0; //全局变量定义,外部连接
int k = 0; //全局变量定义,外部连接
int foo() { return 2;} //全局函数定义,外部连接


  在全局名字空间中,main.cpp中定义 了静态变量i,常量k,及静态自由函数foo等,这些都有内部连接。如果你将这些变量或函数的static或是const修饰符去掉,在连接时就会现 multiply defined symbols错误,它们与a.cpp中的全局变量、全局函数发生冲突。

c)类定义总有内部连接,而非inline类成员函数定义 总有外部连接,不论这个成员函数是静态、虚拟还是一般成员函数,类静态数据成员定义总有外部连接。 

  1.类的定义有内部 连接。如果不是,想象一下你在4个cpp文件中include定义了类Base的头文件,在4个编译单元中的类Base都有外部连接,在连接的时候就会出 错。

  看下面的例子:

//main.cpp

class B //类定义,内部连接
{
 static int s_i; //静态类成员声明,内部连接 
 public:
  void foo() { ++s_i;} //类inline函数,内部连接
};
struct D 
{
 void foo(); //类成员函数声明,内部连接
};

int B::s_i = 0; //类静态数据成员定义,外部连接
void D::foo() //类成员函数定义,外部连接

  cout << "D::foo in main.cpp" <<endl;
}

int main() //main函数,全局自由函数,外部连接
{
 B b;
 D d;
 return 0;
}

//a.cpp

class B
{
 int k;
};

struct D
{
 int d;
};

  In this example, both main.cpp and a.cpp have definitions of class B and class D, but no link error occurs when compiling these two cpp files.

  2. Non-inline member functions of a class (generally, static, virtual) always have external connections, so that when you include the header file of a certain class and use the functions of this class, you can connect to the correct class member function. Above, continue to use the above example, if you change struct D in a.cpp to

struct D //Class definition
{  int d;  void foo(); //Class member function declaration }; void D::foo() //Class member function definition, external connection {  cout << " D::foo in a .cpp" <<endl; }







  At this time, both main.cpp and D::foo in a.cpp have external connections, and a multiple defined symbols error will occur during the connection. 

  3. The static data members of the class have external connections, such as B::s_i in the above example. In this way, when you define the class static data members in main.cpp, if other compilation units use B::s_i, they will be connected to main. .cpp corresponds to s_i of the compilation unit.

  d) Inline functions always have internal connections, no matter what the function is

// main.cpp

inline int foo() { return 1;} //inline全局函数,内部连接
class Bar //类定义,内部连接
{
 public:
  static int f() { return 2;} //inline 类静态函数,内部连接
  int g(int i) { return i;} //inline 类成员函数,内部 连接
};

class Base
{
 public:
  inline int k(); //类成员函数声明,内部连接
};

inline int Base::k(){return 5;} //inline 类成员函数,内部连接
int main(void)
{
 return 0;
}

  If your Base class is defined in Base.h, and the inline function of Base is defined in Base.cpp, then there will be no problem in compilation by including "Base.h" in main.cpp, but it will be during connection. Function k cannot be found, so it is best to put the inline function of the class in the header file, so that every cpp that contains the header file can find the inline function.

  Now that I have an understanding of connections in C++, I can clearly understand what causes connection errors. When you generate an error that cannot be connected when connecting, it means that all compilation units do not have external connections for this entity; when you find multiple connection entities when connecting, it means that there are multiple compilation units that provide the same name. Externally connected entities. At the same time, when designing programs, be careful not to have external connections for only the functions, classes, variables, etc. used by this compilation unit to reduce connection conflicts with other compilation units.

  However, the connection between the template function and the template class is not explained here, and some special situations are not explained (for example, the inline function cannot be inline).

Guess you like

Origin blog.csdn.net/myemailsz/article/details/8670819