• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > 深入分析C++中声明与定义的区别

深入分析C++中声明与定义的区别

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c++类的声明与定义,c++函数声明,c++前置声明,c++未声明的标识符,c++ 函数声明 const等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

        首先谈下声明与定义的区别。
        声明是将一个名称引入程序。定义提供了一个实体在程序中的唯一描述。声明和定义有时是同时存在的。

   如int a;

   extern int b=1;
</div>

    只有当extern中不存在初始化式是才是声明。其他情况既是定义也是声明。

     但是在下列情况下,声明仅仅是声明:

    1:仅仅提供函数原型。如void func(int,int);

    2: extern int a;

    3:class A;

    4:typedef声明

    5:在类中定义的静态数据成员的声明
</div>

   如:

class A 
{ 
  public: 
  static int a;//声明。 
};
</div>

   下列情况下 ,定义仅仅是定义:

   1:在类定义之外,定义并初始化一个静态数据成员。如 A::a=0;

   2:在类外定义非内联成员函数。
     声明仅仅是将一个符号引入到一个作用域。而定义提供了一个实体在程序中的唯一描述。在一个给定的定义域中重复声明一个符号是可以的,但是却不能重复定义,否则将会引起编译错误。但是在类中的成员函数和静态数据成员却是例外,虽然在类内它们都是声明,但是也不能有多个。</div>

如:

        明白了声明与定义的区别,还需要明白 内部链接、外部链接。只有明白了它们你才会知道开头提出的问题。

       在编译时,编译器只检测程序语法和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成目标文件。而在链接程序时,链接器会在所有的目标文件中找寻函数的实现。如果找不到,那到就会报链接错误码(Linker Error)。在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。

      链接把不同编译单元产生的符号联系起来。有两种链接方式:内部链接和外部链接。

      如果一个符号名对于它的编译单元来说是局部的,并且在链接时不可能与其他编译单元中的同样的名称相冲突,那个这个符号就是内部链接。内部链接意味着对此符号的访问仅限于当前的编译单元中,对其他编译单元都是不可见的。

       static关键字作用在全局变量时,表示静态全局变量。但是作用域仅仅在当前文件作用域内。其他文件中即使使用extern声明也是无法使用的。const也类似。

       带有static、const关键字和枚举类型的连接是内部的。

       具有内部链接的符号无法作用于当前文件外部,要让其影响程序的其他部分,可以将其放在.h文件中。此时在所有包含此.h文件的源文件都有自己的定义且互不影响。

       类的定义具有内部链接,由于它是定义,因此在同一编译单元中不能重复出现。如果需要在其他编译单元使用,类必须被定义在头文件且被其他文件包含。仅仅在其他文件中使用class a;声明是不行的,原因就是类的定义是内部链接,不会在目标文件导出符号。也就不会被其他单元解析它们的未定义符号。理解这一点很重要。

     内联函数也具有内部链接。

      在一个多文件的程序中,如果一个符号在链接时可以和其他编译单元交互,那么这个名称就有外部链接。外部链接意味着该定义不仅仅局限在单个编译单元中。它可以在.o文件中产生外部符号。可以被其他编译单元访问用来解析它们未定义的符号。因此它们在整个程序中必须是唯一的,否则将会导致重复定义。

       非内联成员函数、非内联函数、非静态自由函数都具有外部链接。

       内联函数之所有具有内部链接,因为编译器在可能的时候,会将所有 对函数的调用替换为函数体,不将任何符号写入.o文件。

       判断一个符号是内部链接还是外部链接的一个很好的方法就是看该符号是否被写入.o文件。

       前面说的是定义对链接方式的影响,接下来说下声明对链接方式的影响。

       由于声明只对当前编译单元有用,因此声明并不将任何东西写入.o文件。

       如extern int a;

       int func();

       这些声明本身不会影响到.o文件的内容。每一个都只是命名一个外部符号,使当前的编译单元在需要的时候可以访问相应的全局定义。

     函数调用会导致一个未定义的符号被写入到.o文件。如果a在该文件中没有被使用,那么没有被写入到.o文件。而func函数有对此函数的调用。也就会将此符号写入目标文件。此后此.o文件与定义此符号的.o文件被连接在一起,前面未定义的符号被解析。

     上述声明有可能导致该符号被写入目标文件中。但是以下声明并不会导致该符号写入到目标文件中。

如:

typedef int Int;
Class A; 
struct s; 
union point; 
</div>

 
     它们的链接也是内部的。

     类声明和类定义都是内部链接。只是为当前编译单元所用。

     静态的类数据成员的定义具有外部链接。如

class A 
{ 
  static int a;//声明。具有内部链接。 
};
</div>

      静态数据成员a仅仅是一个声明,但是它的定义A::a=0;却具有外部链接。

     C++对类和枚举类型的处理方式是不一样的。比如:在不定义类时可以声明一个类。但是不能未经定义就声明一个枚举类型。

     基于以上的分析,我们可以知道:将具有外部链接的定义放在头文件中几乎都是编程错误。因为如果该头文件中被多个源文件包含,那么就会存在多个定义,链接时就会出错。

     在头文件中放置内部链接的定义却是合法的,但不推荐使用的。因为头文件被包含到多个源文件中时,不仅仅会污染全局命名空间,而且会在每个编译单元中有自己的实体存在。大量消耗内存空间,还会影响机器性能。

     const和static修饰的全局变量仅仅在当前文件作用域内有效。它们具有内部链接属性。

    下面列出一些应该或是不应该写入头文件的定义:

//test.h 
#ifndef TEST_H 
#define TEST_H 
  int a;   //a有外部链接,不能在头文件中定义。 
  extern int b=10;//同上。 
  const int c=2;//c具有内部链接,可以定在头文件中但应该避免。 
  static int d=3;//同上。 
  static void func(){} //同上。 
  void func2(){} //同a。 
  void func3();//可以。仅仅是声明。并不会导致符号名被写入目标文件。 
class A 
{ 
  public: 
   static int e;//可以,具有内部链接。 
   int f;//可以,同上。 
   void func4();//声明,内部链接。同上。 
}; 
  A::e=10;//不可以在头文件中包含具有外部链接的定义。符号名别写入目标文件。 
  void A:func4()//不可以,类成员函数。外部连接。 
{ 
 //,...... 
} 
#endif
 
</div>

      相信大家现在明白为什么只在类型声明成员函数,而不实现它是合法的了。也可以回答为什么类的定义可以放在.h文件中。而类的实现可以放在同名的cpp文件中。老师以前的介绍是说编译器会自动寻找同名的cpp文件。其实是因为由于cpp文件中存储的是成员函数的实现,而成员函数具有外部链接特性,会在目标文件产生符号。在此文件中此符号是定义过的。其他调用此成员函数的目标文件也会产生一个未定的符号。两目标文件连接后此符号就被解析。注意static数据成员应该放在cpp文件中。而不能放在.h文件。

      有内部链接的定义可以定义在cpp文件中,并不会影响全局的符号空间 。但是在cpp文件作用域中要避免定义(并不禁止)没有声明为静态的数据和函数,因为它们具有外部链接。

如

 int a; 
void func() 
{  
    ...... 
} 
</div>

      上述定义具有外部链接可能会与全局命名空间的其他符号名称存在潜在冲突。如果确实需要使用全局的变量或函数。可以为它们加上static关键字。使其作用域局限在当前文件内,具有内部链接也就不会对全局命名空间产生影响。因为内联函数和静态自由函数、枚举以及const类型的数据都具有内部链接,所以它们可以定义在cpp文件中,而不会影响全局命名空间。

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 探讨C++中不能声明为虚函数的有哪些函数
  • 讲解C++中的枚举类型以及声明新类型的方法
  • 深入分析C++中声明与定义的区别
  • 浅析C++中前置声明的应用与陷阱
  • 解析C++浮点数无效值的定义与无效值判定的小结

相关文章

  • 2017-05-28C数据结构之双链表详细示例分析
  • 2017-05-28C语言单链表的实现
  • 2022-04-30C语言字符串指针(指向字符串的指针)详解
  • 2017-05-28operator new在C++中的各种写法总结
  • 2017-08-30C++ 多线程 小记
  • 2017-05-28数组中求第K大数的实现方法
  • 2017-05-28C语言基础知识点解析(extern,static,typedef,const)
  • 2017-05-28深入剖析Android中init进程实现的C语言源码
  • 2017-05-28c语言全局变量和局部变量问题及解决汇总
  • 2017-05-28基于VC中使用ForceInclude来强制包含stdafx.h的解决方法

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 原码, 反码与补码基础知识详细介绍
    • C 语言基础教程(一)颜色加亮
    • VC使用TerminateProcess结束进程实例
    • 总结C语言中const关键字的使用
    • 深入C++四种强制类型转换的总结
    • C++实现将输入复制到输出的方法
    • C语言 makefile学习及实现实例
    • 详解C语言中strpbrk()函数的用法
    • C语言函数语法详解
    • 基于list循环删除元素,迭代器失效的问题详解

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有