C++语法知识小结(持续更新中)
1)在适用构造函数创建对象时,有时会创建临时对象。如
Stock::Stock(const std::string & co,long n,double pr);
在使用时,下面两条语句有根本区别:
Stock stock2=Stock("Boffo Ojects",2,2.0);
stock1=Stock("Nifty Foods",10,50.0); stock1是类对象
第一条语句是初始化,它创建有指定值的对象,可能会创建临时对象(也可能不会,取决于实现,我的电脑不会创建);第二条语句是赋值。像这样在赋值语句中使用构造函数总会导致在赋值前创建一个临时对象。如果既可以通过初始化,也可以通过赋值来设置对象的值,则应采用初始化方式。通常这种方式的效率更高。
2)作用域为类的常量
有时,类声明可能使用字面值30来指定数组的长度,由于该常量对于所有对象来说都是相同的,因此创建一个由所有对象共享的常量是个不错的主意。但下面这样做不可行:
class Bakery
{
const int Months=12;
double costs[Months];
...
};
这是因为声明类只是描述了对象的形式,并没有创建对象。因此,在创建对象前,将没有用于存储值的空间(C++11提供了成员初始化,但不适用于前述数组声明)。有两种方式可以实现这个目标,并且效果相同
第一种:在类中声明一个枚举。在类声明中声明的枚举的作用域为整个类,因此可以用枚举为整型常量提供作用域为整个类的符号名称。可以这样声明:
class Bakery
{
enum{Months=12};
double costs[Months];
....
}
用这种方式声明枚举并不会创建类数据成员。也就是说,所有对象中都不包含枚举。Months只是一个符号名称,在作用域为整个类的代码中遇到它时,编译器将用12来替换。
第二种:使用关键字static。
class Bakery
{
static const int Months=12;
double costs[Months];
...
}
这将创建一个名为Months的常量,该常量与其它静态变量存储在一起,而不是存储在对象中
3)符号常量和常变量的区别
符号常量不占用内存空间,在预编译时就全部由符号常量的值替换了,由于不占有内存空间,故不可对符号常量寻址,enum声明的就是符号常量,而const int Months=12,声明的为一常变量,因为可对Months寻址。
而常变量首先它是变量,占有内存空间,但其值必须在声明时初始化,且其值不可更改,const声明的是常变量,而不是如C++ Primer Plus的3.2节所说的符号常量
4)C++ Primer Plus中程序11_16的一些思考
在11_16中,有一个符号常量Lbs_per_stn。它的由来可参看书中10.6节,它还可以替换为static const int Lbs_per_stn=14;在看到12.7节中声明了一个类Queue,其中有一个const int qsize成员变量(其实就是常量)。它采用成员初始化列表给常量赋值,即在执行构造函数体之前,创建对象时进行初始化。
Queue::Queue(int qs):qsize(qs)
{
front=rear=null;
items=0;
}
那么在程序11_16中,是否也可以采用这种方式,将Lbs_per_stn声明为const int,在构造函数中采用成员初始化列表呢?
class Stonewt
{
const int Lbs_per_stn;
.....
};
Stonewt::Stonewt(double n):Lbs_per_stn(14)
{
......
}
经试验,在11_16中,不能采用这种方式,因为程序中有语句incognito=275;它的工作方式为先调用Stonewt(double)构造函数创建一个临时对象,再采用编译器自动生成的operator=()函数将临时对象的值逐成员复制到incognito中,而const int incognito属于成员变量,它已在生成对象时初始化为14;const变量是不能再被赋值的;故在编译时会出现operator=()函数在Stonewt中不可用导致错误。
若程序中没有incognito=275;则这种采用成员初始化列表的方式是可用的。
总结:若想采用把一个对象赋值给另一个对象,则成员变量中必不能出现常变量const,因为它只可初始化,不能再次被赋值。而enum{Months=12};则是定义了一个符号常量,在编译时,编译器会自动把Months替换为12;而static const int Lbs_per_stn=14;则是定义了一个名为Months的常量,该常量为静态,与其它静态变量存储在一起,而不是存储在对象中,故此时也可利用=赋值。
5)指针和数组名的区别
char * p="abcdefg";和char str[]="abcdefg";str和指针p都指向字符串的首地址,这一点没有区别。但是,str给字符串"abcdrfg"分配了内存空间,该字符串存储在该内存空间中,但是p指针并没有为字符串分配内存空间,字符串"abcdefg"在内存中的存储由系统分配,指针p在32位机中只占有4个字节,即所有指针类型的占用空间单位。此时,指针p指向的时字符串常量"abcdefg",可以改变指针指向的值,但不能为指针赋值。如
char *ps=p+4;
char *pt=p+2;
*pt='L'; (1)
*pt++=*ps++; (2)
其中(1)和(2)是不可以赋值的,虽然编译时没有错误,因为"abcdefg"对p来讲是一个字符串常量。但是,在这种赋值对数组来说是可以的
char str[]="abcdefg";
char *ps=p+4;
char *pt=p+2;
*pt='L'; (3)
*pt++=*ps++; (4)
(3)和(4)都是可以正常运行的。 一定要注意指针和数组的区别!!!!
(6)函数参数传递问题
在传递函数参数时,若未声明为引用,则是按值传递,即使参数为指针。这里一定要区分参数为指针和参数为数组的区别!!!数组名作为参数时,也是地址,但此时对数组的操作是对原来数组的操作,这并不违反按值传递的原则,传递时,函数生成一个与数组名类型相同的指针,数组名把值传递给该指针,这步就是按值传递,只是该指针也指向原数组的内存空间,所以是对原数组进行操作。指针作为函数参数时,也是按值传递的,在内存中会有两个指针变量,他们指向同一块内存区。!!!
最新文章
- 页面中调用系统常用的对话框需要用到的classid
- JSP动作元素——————理论篇
- Qt on Android:创建可伸缩界面
- java 深入技术六(Map)
- php面试题及答案收藏(转)
- POJ 1986 Distance Queries(Tarjan离线法求LCA)
- 《BI项目笔记》用Excel2013连接和浏览OLAP多维数据集
- seajs加载jquery时提示$ is not a function该怎么解决
- zepto源码--matches--学习笔记
- windows7下实现局域网内文件共享
- wbadmin与vssadmin
- 重拾C,一天一点点
- 12_CXF入门
- 【转载】db blocks gets &; consistent gets
- __str__
- HTML5 画布参考
- 一个用于每一天JavaScript示例-SVG中间javaScript画廊
- Ubuntu16.04 server下配置MySQL,并开启远程连接
- Microsoft Visual Studio 2012正式版官方下载
- 【Machine Learning in Action --5】逻辑回归(LogisticRegression)