啥叫内连接 外连接

我们知道编译的时候(假如编译器是VS),是以源文件cpp文件为单位,编译成一个个的obj文件,然后再通过链接器把不同的obj文件链接起来.

简单的说,如果一些变量或函数的定义是内连接的话,链接器链接的时候就不会拿它们去与obj比较看有重复定义不,一个源文件中的extern声明的变量或函数也不能使用另外一个源文件中的内连接的变量或函数.而如果是外连接的话则需要在不同的obj中比较是否有重定义的.除了做这样的检查外,链接器还会查看通过extern修饰的变量或函数声明在其他obj中的定义.

cpp源文件与h头文件关系

我们知道C++支持多种编程范式,可以完全用采用面向过程,不去用类,当然了很少有人这样做,一般是结合面向过程与面向对象.

那假如有一些处在不同源文件中的变量和函数(不是类中的变量成员或成员函数),我们要使用不同源文件中的变量或函数时咋整呢? 在面向对象中我们使用一个个类的时候自然是用头文件引用下就OK.但现在没有类,只是一个个变量和函数,也能用引用头文件吗 ? 这得看情况,有时可以,有时不行.如果头文件中只有外部声明没有任何定义,那引用头文件完全没有问题.如果头文件中有定义的话,如果只被一个cpp文件引用则没问题,如果被多个cpp文件引用就会出现重复定义的错误.(注:编译器是以cpp文件为单位编译,如果某个h头文件没有被引用的话相当于被抛弃不用了.引用头文件时预编译时只是简单的把头文件复制到引用它的cpp文件中.)

extern外部声明

假如在有one.cpp和two.cpp两个源文件.

//one.cpp中

---------------------------------------------------

#include <iostream>

using namespace std;

int number = 123;  //number的定义 .或者写成extern number = 123;当有赋值时,实际上extern失去了应有的作用.所以加不加没影响.

void Print() {cout<<"hi,i am one.cpp"<<endl;}

//two.cpp中

--------------------------------------------------------

#include <iostream>

using namespace std;

extern int number;//这就是所谓的外部声明,此处extern不可省.另外此处绝对不能赋值.如果写成extern int number = 88;会报错是重复定义.

extern void Print(); //此处extern可以省略.

cout<<number;  //结果为123

Print(); //输出i am one.cpp

在two.cpp中是怎么得到one.cpp中的number的值的呢,由于用extern int number这样声明了下,表明number在其他源文件中有定义,链接器就会帮助去其他源文件中找的.

假如把上面two.cpp中的extern关键字去掉. 编译时不会出错.但链接时出错了,重复定义了.因为one.cpp中已经定义了个number,不能再定义一个相同的了.

static 内部连接

上面的例子中我们知道one.cpp和two.cpp中同时写上int number会出错,说重复定义了.但如果这样

//one.cpp中

static int number = 123;

//two.cpp中

static int number;  //没显式赋值,会默认赋予0

此时却不会出错.因为定义变量时默认是外部连接的.而加上关键字static表示是静态变量,是内部连接,链接器不会去看不同cpp编译成的obj文件中有重名的静态变量不.

当用static修饰后就不能再使用extern修饰了.

//one.cpp中

static int number = 123;

//two.cpp中

extern int number;

cout<<number;

此时会出错,因为extern声明的number找不到定义.因为one.cpp的number用static修饰表明是内连接了.

const关键字

//one.cpp中

const int number = 123;

//two.cpp中

const int number = 321;

这里达到的效果与static一样,都属于内部连接,所以不会出错.唯一不同的时const表示常量,定义时必须显式赋予值,且赋值后不能再改变它的值.

不过const还有另外一个特性就是可以和extern一起用.

比如在two.cpp中这样写

extern const int number;

cout<<number; //运行会报错,会说找不到定义.需要把one.cpp中改为extern const int number = 123;才行.

//正确输出的值是one.cpp中的number值123

inline与static函数也是内部连接的

//one.cpp中

void Test() { }

//two.cpp中

void Test()  { }

这样编译时会报错,重复定义了.但如果把上面的两个void Test都改成inline void Test() { }或者static void Test() { }则不会出错.//注意这里讲的inline函数指的是全局函数,不是类里面的inline函数.

所以函数跟一般变量差不多.没任何修饰的就默认是外部连接,有static修饰的则是内部连接.另外没有const函数这一说,只有在类中才可以在函数后面加个const来修饰

转自 http://blog.csdn.net/weiwenhp/article/details/8598342

类定义总有内部连接,而非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; };

  在这个例子中,main.cpp与a.cpp中都有class B和class D的定义,但在编译这两个cpp文件时并不发生link错误。
  2.类的非inline成员函数(一般,静态,虚拟都是)总有外部连接,这样当你include了某个类的头文件,使用这个类的函数时,就能连接到正确的类成员函数上,继续以上面为例子,如果把a.cpp中的struct D改为

struct D //类定义

{

 int d;

 void foo(); //类成员函数声明

};

void D::foo() //类成员函数定义,外部连接

{

 cout << " D::foo in a.cpp" <<endl;

}

  这时main.cpp与a.cpp中的D::foo都有外部连接,在连接就会出现multiply defined symbols错。
  3.类的静态数据成员有外部连接,如上例的B::s_i,这样当你在main.cpp中定义了类静态数据成员,其它编译单元若使用了B::s_i,就会连接到main.cpp对应编译单元的s_i。
  d)inline函数总有内部连接,不论这个函数是什么函数

// 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; }

  如果你的Base类是定义在Base.h中,而Base的inline 函数是在Base.cpp中定义的,那么在main.cpp中include "Base.h"编译不会出现问题,但在连接时会找不到函数k,所以类的inline函数最好放到头文件中,让每一个包含头文件的cpp都能找到inline函数。
  现在对c++中的连接有了一个认识,能清楚的知道是什么原因产生连接时错误。当你在连接时产生连接不到的错误,这说明所有的编译单元都没有这个实体的外部连接;当你在连接时发现有多个连接实体,这说明有多个编译单元提供了同名的有外部连接的实体。同时,在进行程序设计时,也要注意不要使只有本编译单元用到的函数、类、变量等有外部连接,减少与其它编译单元的连接冲突。

C++ 内连接与外连接 (转)的更多相关文章

  1. 你真的会玩SQL吗?和平大使 内连接、外连接

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  2. mysql,SQL标准,多表查询中内连接,外连接,自然连接等详解之查询结果集的笛卡尔积的演化

    先附上数据. CREATE TABLE `course` ( `cno` ) NOT NULL, `cname` ) CHARACTER SET utf8 NOT NULL, `ctime` ) NO ...

  3. SQL - 内连接与外连接

    PDF下载地址:SQL-内连接与外连接.pdf 连接查询在关系型数据库中经常用到,是多表联合查询的基础. 主要包含:内连接,外连接,交叉连接. SQL - 内连接与外连接 内连接 等值连接 不等值连接 ...

  4. SQL中的连接可以分为内连接,外连接,以及交叉连接 。

    SQL中的连接可以分为内连接,外连接,以及交叉连接 . 1. 交叉连接CROSS JOIN 如果不带WHERE条件子句,它将会返回被连接的两个表的笛卡尔积,返回结果的行数等于两个表行数的乘积: 举例, ...

  5. 【SQL】SQL中笛卡尔积、内连接、外连接的数据演示

    SQL的查询语句中,常使用到内连接.外连接,以及连接的基础--笛卡尔积运算. 在简单的SQL中,也许我们还分辨清楚数据如何连接,一旦查询复杂了,脑子也犯浆糊了,迷迷糊糊的. 本文,简单以数据形式记录连 ...

  6. 转:SQL的内连接与外连接

    参考:http://www.cuiyongjian.com/post-130.html 在oracle的SQL语句常用的连接有内连接(inner join),外连接(outer join)等,内连接又 ...

  7. 【Oracle学习笔记-4】内连接和外连接的区别

    参考链接(非常棒) 摘要 下面主要以两个例子进行说明: 例子1: 表A结构如下: select * from A | 表B结构如下: select * from B 两个表要做连接,就必须有个连接字段 ...

  8. SQL的内连接与外连接

    转自:http://blog.csdn.net/killerggf/article/details/6216102 有两个表A和表B.  表A结构如下:  Aid:int:标识种子,主键,自增ID   ...

  9. SQL Server中内连接和外连接的区别

    SQL Server中内连接和外连接的区别 假设一个数据库中有两张表,一张是学生表StudentInfo,一张是班级表ClassInfo,两张表之间用ClassId字段进行关联. 如果用内连接,正常的 ...

  10. 详解SQL Server连接(内连接、外连接、交叉连接)

    在查询多个表时,我们经常会用“连接查询”.连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志. 什么是连接查询呢? 概念:根据两个表或多个表的列之间的关系,从这些表中查询数据 ...

随机推荐

  1. windows10添加开机自启动程序

    1. 将要启动的程序创建快捷方式 2. 将创建的快捷方式放到以下文件夹中 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup

  2. LightOJ 1030 Discovering Gold (期望)

    https://vjudge.net/problem/LightOJ-1030 题意: 在一个1×N的格子里,每个格子都有相应的金币数,走到相应格子的话,就会得到该格子的金币. 现在从1格子开始,每次 ...

  3. UVa 11383 少林决胜(二分图最佳完美匹配)

    https://vjudge.net/problem/UVA-11383 题意: 给定一个N×N矩阵,每个格子里都有一个正整数W(i,j).你的任务是给每行确定一个整数row(i),每列也确定一个整数 ...

  4. @ResponseBody和@ResponseEntity注解

    如果需要返回json格式的数据,那么添加该注解就行了@ResponseBody对于ResponseEntity确切的说是ResponseEntity ,如果你即需要返回数据,又需要确定数据的状态,就用 ...

  5. 雷林鹏分享:Ruby CGI 编程

    Ruby CGI 编程 Ruby 是一门通用的语言,不仅仅是一门应用于WEB开发的语言,但 Ruby 在WEB应用及WEB工具中的开发是最常见的. 使用Ruby您不仅可以编写自己的SMTP服务器,FT ...

  6. dva subscription的使用方法

    import { routerRedux } from 'dva/router' export default { namespace: 'notice', state: { notices:[], ...

  7. python批量给云主机配置安全组

    python批量给云主机配置安全组 用公有云的思路去思考去实现一个安全稳定.可伸缩和经济的业务构架,云运维是有别与传统运维的,比如说了解公有云的都知道安全组的概念,安全组跟防火墙功能很相似,那我的机器 ...

  8. C#如何弹出输入框

    在C#中,进行windows窗体应用程序编程的时候,经常需要弹出输入框,输入密码,输入文本之类的.然而,C#中没有直接弹出输入框的语句,MessageBox只能显示一段消息而不能输入.我们需要调用Mi ...

  9. 如何导入数据到Mysql

    有两种方法: 1.如果是.sql后缀的数据库文件,使用phpmyadmin中的导入功能导入即可,导入前需要新建数据库名. 2.如果导入的是文件夹(内含.frm,.myd,.myi,.opt类型文件), ...

  10. 201621123010《Java程序设计》第7周学习总结

    1. 本周学习总结 1.1思维导图:Java图形界面总结 2.书面作业 1. GUI中的事件处理 1.1 写出事件处理模型中最重要的几个关键词. addActionListener(new Actio ...