关于C++的变量和类的声明和定义
什么是变量?变量或者叫对象,是一个有具名的、可以供程序操作的存储空间。这里具名是指变量是有名字的,可供操作是指能进行加减乘除或者输入输出等操作,存储空间则是指有一块属于它的内存空间。
为了便于说明,标题和后面的内容将对象分为两种。对于内置的,文章称作为变量,对于自定义的,称之为对象。
第一个问题:在C++中,什么是定义,什么是声明?
①定义:用于为变量分配存储空间,还可为变量指定初始值。在程序中,变量有且仅有一个定义。
②声明:用于向程序表明变量的类型和名字。在程序中,变量可以有多个声明。
定义也是声明:当定义变量时我们声明了它的类型和名字。
上面的这些内容很容易理解,很多情况下,定义就是声明,由于C++支持分离式编译,因此一个C++程序允许别分成许多块,由这些块共同组成完整的程序。既然程序可以分成多块,那么如果要在所有块之间共用一个变量,那就要能够在这些块之间共享代码。为了支持这种分离式编译机制,C++中就将声明和定义区分开来了。
第二个问题:定义也是声明,那么如果仅仅声明?
回答这个问题之前,需要了解什么是作用域,这里假定你已知晓C++的作用域知识。
在需要声明一个变量之前,先想一想为什么需要声明变量?因为程序需要使用定义在别处(通常是别的文件中)的变量。这里使用别处的变量暗含了一个意义,这个变量应当是个全局变量,因为当前作用域找不到,所以需要去别的地方找,而别的地方定义的变量应当全局变量,能够被我看到(这里只考虑全局变量,其他情况暂不考虑)。
既然变量已经在别的地方定义过了,而且变量有且仅有一个定义,那么我不能再次定义而只能声明了,如何声明?
声明的方式是使用extern关键词,形如extern int i,这里有了关键词extern的修饰,因此是一个声明,而不是定义。从这个声明中,得知了变量的类型和名字,但是没有分配内存。
假如给上面声明的变量一个值,那还是不是声明呢?回答是:不是。如果这样extern int i = 10;那么这里的extern关键词就失效了,这句代码则变成了定义。
从上面两个问题中,我们可以知道一个频繁被提及的问题:为什么不能在头文件中定义全局变量?
因为变量只能被定义一次,包含了头文件的源文件,都将会定义同样的全局变量,造成冲突,所以,头文件中不能定义全局变量。
由此引申的一个问题:定义在一个源文件中的全局变量,如何让程序所有的其他块使用?回答是要么每次在每个块(即源文件)中手动使用extern声明,要么使用extern关键词仅仅声明该全局变量,然后将声明放在一个头文件中,该头文件被所有其他快使用。
接下来是类声明和定义的内容了。
同样地,什么是类?
现在如果总结出类的特点,估计初学者会觉得很抽象或者难以理解。我们先来说说在C++中如何定义类?
定义类的语法如下:
首先是关键词class或者struct,两种区别是默认访问权限。上面我们定义了一个类A_example,定义了一个类A_example也就是定义了一种新的类型A_example,就像int一样,它是一种类型。
class A_example
{
public:
int i;
double d;
float f = 10.0f;
static char c = 'A'; };
也就是说上面是定义了一种类型,那么这个类里面的int i和double d是定义还是声明?答案是声明。
对于其中的float f = 10.0f;是声明还是定义呢?答案是声明。虽然这里声明的同时赋予了值,但它仍然是一个声明。
对于static char c = 'A';是声明还是定义?答案还是声明!如果你认为它是定义,那么你可以试试直接编译能否通过,编译器通常会这样告诉你:
error: non-const static data member must be initialized out of line(大致意思是,你并没有初始化,你需要在类外进行定义并初始化,因为类里面的只是声明而已)
从以上我们能很直观的感受到一个特点:定义一个类时,对于其中的数据成员,不论有无默认值,也不论是static还是非static的,我们只是描述了一个类,注意,仅仅是描述了类,也即,我们只知道它含有哪些类型,如果还定义了函数成员,我们还描述了这种类型的操作。
在A_example的定义中,我们并不知道这个类的具体情况,我们只知道它的属性,它含有什么类型,但不知道具体相应类型变量的值大小。对于默认值,只是一旦用这个类去实例化一个对象,就像int i那样,给对象一个默认值而已。
在C语言中则更明显,为什么使用结构体struct定义一种类型时,不允许对结构体中的变量赋予默认值?原因就是,仅仅定义了类型而已,只是一些声明而非定义,声明没有开辟内存空间,你给它默认值,它没有地方存储,因此C语言中结构体是没有默认值的。
因此,再看下面这段话,相信会有点感觉:
在C++中, 用 "类" 来描述 "对象", 所谓的"对象"是指现实世界中的一切事物。那么类就可以看做是对相似事物的抽象, 找到这些不同事物间的共同点, 如自行车和摩托车, 首先他们都属于"对象", 并且具有一定得相同点, 和一些不同点, 相同点如他们都有质量、都有两个轮子, 都是属于交通工具等。"都有质量"、"两个轮子"属于这个对象的属性, 而"都能够当做交通工具"属于该对象具有的行为, 也称方法。
类是属于用户自定义的数据类型, 并且该类型的数据具有一定的行为能力, 也就是类中说描述的方法。通常来说, 一个类的定义包含两部分的内容, 一是该类的属性, 另一部分是它所拥有的方法。以 "人类" 这个类来说, 每个人都有自己的姓名、年龄、出生日期、体重等, 为 人类 的属性部分, 此外, 人能够吃饭、睡觉、行走、说话等属于人类所具有的行为。
上面是类的定义,那么类的声明呢?
类的声明和普通的内置类型相似,普通的内置类型是声明变量,即告知变量的类型和名字。对于类声明,形如class A_example,这里class表明是一种类型,而A_example则是具体的类型名。
从文章最开头,我们知道:不能在C++的头文件中放置变量的定义,因为变量只能定义一次,为什么类的定义可以放在头文件中呢?在类的定义部分我们又得知,类定义只是定义了一种类型,也即说明了一个类,并没有实际定义类的对象,定义的是类,定义类描述的是新的类型,而描述新类型并不会开辟内存空间去存储这样一种新类对象,因此类定义可以存放在头文件中。
关于C++的变量和类的声明和定义的更多相关文章
- 你好,C++(32) 类是对现实世界的抽象和描述 6.2.1 类的声明和定义
6.2 类:当C++爱上面向对象 类这个概念是面向对象思想在C++中的具体体现:它既是封装的结果,同时也是继承和多态的载体.因此,要想学习C++中的面向对象程序设计,也就必须从“类”开始. 6.2. ...
- C++类模板声明与定义为何不能分开
我们用C++写类的时候,通常会将.cpp和.h文件分开写,即实现和声明分开写了:但在C++的类模板中,这种写法是错误的. 在<C++编程思想>的第16章的"16.3模板语法&qu ...
- 面试问题之C++语言:类模板声明与定义为何不能分开
C++中每个对象所占用的空间大小,是在编译的时候就确定的,在模板类没有真正的被使用之前,编译器是无法知道,模板类中使用模板类型的对象的所占用的空间的大小的.只有模板被真正使用的时候,编译器才知道,模板 ...
- 一个完整的C++程序SpreadSheet - 1) 类的声明和定义
1. SpreadsheetCell.h #pragma once #include <string> class SpreadsheetCell { public: void setVa ...
- c++新特性实验(5)声明与定义:属性列表(C++11 起)
1.初识属性 1.1 实验A: noreturn 属性 [[ noreturn ]] static void thread1(void *data){ cout << "nore ...
- C++将模板的声明和定义放置在同一个头文件里
1. 一个类: 头文件用于保存类的声明:定义文件保存类的实现. 2. 分离编译模式: 允许在一个编译单元(.cpp文件)中定义函数.类型.类对象等,然后在另一个编译单元中引用它们.编译器处理完所有 ...
- C++ static静态成员变量在类中仅仅是声明
今天写代码时看到: 图1的3个静态成员变量在类中仅仅是声明,没有定义以及分配内存:必须在类外,图中就是cpp中,定义分配内存,才能使用
- C++11类内static成员变量声明与定义
众所周知,将一个类内的某个成员变量声明为static型,可以使得该类实例化得到的对象实现对象间数据共享. 在C++中,通常将一个类的声明写在头文件中,将这个类的具体定义(实现)写在cpp源文件中. 因 ...
- JSP变量、方法和类的声明,JSP程序片,JSP表达式
参考文章 http://c.biancheng.net/view/1431.html http://c.biancheng.net/view/1433.html http://c.biancheng. ...
随机推荐
- poj 3592 Instantaneous Transference
http://poj.org/problem?id=3592 #include <cstdio> #include <cstring> #include <algorit ...
- ASP.NET状缓存Cache的应用-提高数据库读取速度
原文:ASP.NET状缓存Cache的应用-提高数据库读取速度 一. Cache概述 既然缓存中的数据其实是来自数据库的,那么缓存中的数据如何和数据库进行同步呢?一般来说,缓存中应该存放改 ...
- Xamarin Studio –Project not built in active configuration
当我们加载项目以后如果出现以下项目提示 处理方式如下: 解决方案右键->options 配置->configuration mappings->勾选构建的ios项目 项目右键-> ...
- Linux&shell之结构化命令进阶
写在前面:案例.常用.归类.解释说明.(By Jim) for命令重复一系列的命令是一种常见的编程实践. #!/bin/bash # basic for command for test in A B ...
- 维基百科上—数据仓库、数据挖掘、OLAP三者之间的区别
数据仓库可以作为数据挖掘和OLAP等分析工具的资料来源,由于存放于数据仓库中的资料,必需经过筛选与转换,因此可以避免分析工具使用错误的资料,而得到不正确的分析结果. 数据挖掘和OLAP同为分析工具,其 ...
- jQuery Ajax 实例 ($.ajax、$.post、$.get)【转载】
本文转载自:http://jun1986.iteye.com/blog/1399242 Jquery在异步提交方面封装的很好,直接用AJAX非常麻烦,Jquery大大简化了我们的操作,不用考虑浏览器的 ...
- python自动化测试遇到的零零碎碎
1.需求: 提取xx.py中所有的函数名,形成一个类似于索引的参考. 解决方式: grep "def" *.py| awk '{print $2}'|awk -F ':' '{pr ...
- java的异常处理简介
异常概述 任何一种程序设计语言设计的程序在运行时都有可能出现错误,例如除数为0,数组下标越界,要读写的文件不存在等等. 捕获错误最理想的是在编译期间,但有的错误只有在运行时才会发生. 对于这些错误,一 ...
- 对于AttributeError: 'Flask' object has no attribute 'cli'的解决办法
版权声明:本文为博主原创文章,未经博主允许不得转载. 环境flask-script2.0.5.flask0.10.1 运行官方文档sample 出现问题 c:\kk\flask\examples\fl ...
- UITabBarController 标签栏控制器
接上篇导航控制器UINavigationController 接下来是UITabBarController 标签栏控制器 先来看一下UITabBarController的结构 从图上可以看出控制器分为 ...