声明和定义的区别
因为C++支持分离式编译,也就是将代码放到多个不同文件中,那为了在不同文件中使用相同的数据,就必须将声明和定义分离开。
首先,定义指的是为变量分配存储空间,真真正正地创造物理上的二进制代码。如下列代码
#includeusing namespace std; int fc(){ //以下三行均为定义加声明 int i=0; int j=1; int k; //以下为赋值操作, i = 100; j = 5; }
而声名的意义是使得名字为程序所知,并不分配储存空间。
在讲这几个关键字之前,我们先要弄懂头文件、源文件是干啥的(非常重要!!),见:头文件源文件的意义
extern关键字
比如cod1.cpp声明并定义了一个数据a, 则cod1.cpp可以直接使用a,但是如果想要在其他文件如cod0.cpp,cod2.cpp中使用数据a,则必须在其他文件先声明a。所以,定义只能有一次,而声明可以有多次。具体地,我们在cod1.cpp中将a定义为全局变量,在cod1.h中用extern进行声明(表示数据a定义在其他文件),然后只要想使用数据a的程序只需要#include “cod1.h”(函数也同理)。举个栗子如下图,cod.cpp为主文件,想调用cod1.cpp
#include "cod1.h"
int a = 3;//定义 a
//定义函数fun()
void fun(){
cout << "fun" <
using namespace std;
extern int a;//声明a
void fun();//声明fun
#endif
#include
#include "cod1.h"//cod1.h中有a 和fun的声明,表示在本文件中可以使用
using namespace std;
int main(){
fun();
cout << a <
但是如果我不想让cod1.cpp中定义的数据被用于其他文件怎么办,方法就是使用静态变量static.
static关键字
首先我们要理解c++中完整程序的内存分布。由高地址到低地址依次是栈区、堆区、静态区(全局区)、常量区,代码区。由static修饰的静态变量会放入静态区,特点是只进行一次内存分配,直到程序全部结束后释放。
static关键字的用途主要分为以下几类:
1、修饰全局变量或函数,表明该全局变量不能在其他文件中使用定义域仅为本文件,这样就解决了上面不用于其他文件问题。
2、修饰局部变量,表明该值仅在第一次定义的时候分配内存,不会因为该函数的结束而丢失值(直到全部程序执行完才被释放)
沿用上面的例子
#include "cod1.h"
int a = 3;//定义 a
static b = 4;//将全局变量b定义为静态全局变量,表示其不能在.h文件中用extern声明,其作用域仅限于本文件
//定义函数fun()
void fun(){
cout << "fun" <
using namespace std;
extern int a;//声明a
void fun();//声明fun
#endif
#include
#include "cod1.h"//cod1.h中有a 和fun的声明,表示在本文件中可以使用
using namespace std;
void codfun(){
//定义局部静态变量count,只在第一次调用该函数的时候分配内存,
//直到main()函数结束才释放,作用域仅限本函数
static int count = 0;
cout << count <
const关键字
const关键字表示修饰的为常量类型,也就是不允许被修改的值。需要注意:
1、const引用不能赋值给非const引用。
2 const类型默认为static类型的,也就是作用域仅在本文件中,但是仍然可以像普通类型一样 在.h文件中用extern声明,表示可以在多文件中使用,这样就取消了默认的static类型。
#ifndef COD1_H_
#define COD1_H_
#include
using namespace std;
extern const int b;
void fun();
#endif
#include "cod1.h"
const int a = 1;
const int b = 2;
void fun(){
cout << a<<' '<
#include "cod1.h"
using namespace std;
const int a = 6;
int main(){
fun();// 1 2
cout <
上述代码可以看到cod1.h文件中,我将 b声明为了extern类型,这意味着所有include该头文件的代码都可以使用b。
注意,上面写的可用于c和c++,但在c++中,static还可用于类的数据成员以及成员函数。
静态数据成员表示该数据声明周期大于每个实例,在所有实例中共享(同一内存),而普通数据成员每个实例都会分配内存。静态函数与静态数据一样。
注意:静态成员函数只能访问静态数据及函数而不能访问非静态数据和非静态函数(因为非静态数据每个实例不一样),而非静态函数可以访问非静态数据和函数,也能访问静态数据和函数。
这样我们就简单介绍了extern static const是干啥的。
但重点是如何声明和定义使用他们,必须遵守哪些规则。
#include
using namespace std;
class base{
public:
static int i;//静态成员
//静态函数
static void p{
}
}
int main(){
fun(); //"fun"
cout << a <
static、const的定义与声明
首先的首先,必须要搞清楚.h 文件和.c文件以及#include<***.h>是干啥的,定义和声明到底应该写在哪?#ifndef #ifndef #endif有啥用?就是我们一开始的那个链接
从上述知,c++中变量或者函数只能进行一次定义,而可以进行多次声明。但是也有3类可以在不同文件中进行多次定义,
1、inline函数,
2、类函数,
3、static,const修饰的变量和函数。
如上面的代码段中,cod1和cod2中同时定义了const int a,而且给他赋了不同的值,而且编译器没报错,如果同时定义一个没有static或者const修饰的 int i就会报错,为什么会出现这种情况?
首先我们要理解,规范的cpp代码应该是.h文件只包含变量、函数、类的声明,而相应的定义应该放到cpp文件中,这样其他文件使用函数的时候只include .h文件就可以,就相当于在其他文件中又声明了一次函数,就可以直接使用了。如果将函数或者变量的定义放到.h文件中,因为有多个文件include 该.h文件,就会造成重复定义的错误。这里要区分开#ifndef #define #endif 即使你加了这些东西会报错。
但是也有例外,比如static修饰的全局变量,因为static将其作用域限定在本文件中,所以不同的文件允许定义相同名称类型的static数据(最好不要这么做,因为没啥意义,定义成不同名字的还好一点),为各个数据分配不同的内存(const类型默认为static的)。所以实现的方法有两种,
1、在需要的cpp文件中声明并定义
2、在.h文件中定义,需要的include .h文件
需要注意的是,不能在.h 文件 和include 该.h 文件的cpp文件中同时定义!而且各个数据之间是独立的(地址不同)
#ifndef COD1_H_
#define COD1_H_
#include
using namespace std;
static int c = 1;
void fun();
#endif
#include "cod1.h"
static int a = 1;
void fun(){
a++;
c++;
cout << a<<' '<
#include "cod1.h"
using namespace std;
static int a = 5;
int main(){
fun();
c--;
cout <
可以看到cod.cpp与cod1.cpp都定义了相同的变量a, 或者cod1.h中定义变量c, 在两个cpp文件中引用c,都是允许的,而且对其的操作互不干扰,由static修饰的函数也是一样。const一般只在类内修饰函数,不作讨论。但是如果你在两个cpp文件中都定义不加static 的全局变量 int i=1, 或者在.h文件中定义 int j=1.这种情况就会报错,因为最后链接时全部的cpp文件都要放到一块,多次重复定义全局变量是不允许的(无论是多个文件定义还是同一文件定义多次)。
如果你在cod.h文件和cod.cpp文件同时定义 static int k = 0, 而你的cod.cpp又引用了cod.h这些也会报错(同一文件是不允许多次定义相同static数据的)。所以为了避免这些问题,应该严格遵守头文件声明,源文件定义的写法。也就是下面说的东西。
static、const修饰类成员函数或者数据时如何定义,在哪定义?
首先最最最重要的,全部遵守在头文件声明,源文件定义肯定不会出错。
但是c++又允许我们上面说的3类在头文件中定义,这就会造成一些定义上的要求。(类成员函数在头文件定义被认作内联函数,内联函数为什么可以在头文件定义挖坑以后说)。
那是不是所有的函数都能在头文件定义?答案是否定的,由static修饰的静态成员函数,只能在源文件中定义。静态成员函数与普通的静态函数不同,普通的静态函数在头文件中定义后,如果有多个源文件include它,它就为每个源文件分配一个该函数,而静态类成员函数只能有一个,如果在头文件中定义,就会报错。const函数(不能修改成员变量的函数)与普通成员函数一样,可以在头文件定义。
至于成员数据:
普通成员数据:在构造函数中(头文件或源文件)初始化,或者创建实例后初始化
static 成员数据:只能在源文件中初始化,原因与静态成员函数相同
const成员数据:只能在构造函数初始化列表中定义(构造函数在哪它就在哪,不同实例可以有不同值)
static const成员数据(等同const static):与static相同,只能在源文件中初始化
写的有点乱,最后总结一下
1、先要搞懂.h .c #include是干啥的,也就是源文件头文件
2、时刻掌握,定义只能有一次,而声明可以有多次(然后自己看看会不会发生重复定义的错误,如果不会为什么不会,如果会,为什么会!!!)
3、因为2的原因,我们时刻应该遵守在头文件声明,在源文件定义,然后引用头文件进行操作。
4、但是c++又允许3类东西在头文件中定义(最好还是不这么做),你要搞清楚为什么允许。
4、c++既然允许静态函数,类函数在头文件定义,那为什么又不允许静态的类函数在头文件定义呢?
5、已经知道了各种类函数如何定义,那各种类数据如何定义在哪定义呢?
顺着上面思路捋一下,会比较清楚
全文完。。。如果有参考价值的话点个赞呗。
参考
《C++ prime》
类成员数据与函数(有写错的地方)
static成员函数



