转载的一篇文章:
本篇主要写给对const语法理解存在误区的c++学习者,希望所有对这方面比较模糊的朋友可以阅读并从中找到一些答案。
。
2004-11-19 21:00
Const 最早想法是用于取代预处理器#define 这个宏,从而形成
常量的概念。针对常量const对象,const指针及指向const的指针,函数const类型参数,const 函数返回类型, const类成员,及const成员函数,及对const最后理解的一些总结来描述 const。
① const对象和const类型的对象
对于这两个概念的描述如下
1. int const Object; //Object是一个const量是不可以被修改 Object = 2;Error
2. const int Object; //Object是 const int型他所存放的内容不可以被修改
对于1,2这两种const用于对象,表述虽然不同但是效果是一样的。因为对象本身存放着内容对对象的改变就是对于对象内容的改变,同样改变后者也是在改变前者。所以语义上一样的。
② const指针 和 指向const的指针 及两者结合
对于三个概念描述如下
1. int* const p; //指针p是const不能被修改 例如p++; //修改p本身会Error
//修改p指向内容 *p = 2; //OK
2. const int* p; //p是指向一个整形常量的指针指向的内容不可以改变 p++;//OK
// *p = 2; //Error
3. const int* const p; //指针p本身是不能被修改并且p所有有效的内容也不能被
//修改 *p = 2; Error 和 p++; Error
③ const 参数修饰 和 参数返回类型的const修饰
1.const 参数修饰
此时函数参数修饰 const的具体用法 ① ②中用法是一样的
例如 void Fun( const int I ) { I++;} //Error不能修改常量I
2.const修饰函数返回类型用法也是类似于 ①②中,仅仅修饰的对象变化变成一个返回对象
例如:const int Fun() { static int I; return I;}
int Res = (Fun())++ //Error不能修改常量返回对象
④ const类成员 和 const 成员函数
1. const成员
类const成员在构造期间会允许被初始化并且在以后不能被改变。我们就可以知道类const成员和一般const 变量是有所不同的,类const成员是对应于每个对象而言才有意义。因为他在构造期被初始化,只有当类实例化后才会进行构造。所以类const成员可以这样描述: 在类的每一次实例化时被初始化,在这个对象的生存周期中不可改变。
2. const 成员函数
描述: void Class::MemberFun() const {}; //此时这个const修饰的this所有类成员变量都不允许在这个函数体作用后被修改。这在设计上会带来一些好处,能防止你意外的处理带来的问题。
总结:
<1> const 常量 一般编译器不会分配空间只是维护一张表。而当extern 外部引用这个常量或者“&”对这个常量取地址时,编译器才会为其分配地址。Const本身的机制比较复杂。
<2> const 记忆法则 const修饰后面一个最近的名称。我曾初学的时候被const 修饰搞的糊里糊涂,后来慢慢的总结我觉得这样理解最容易的。
例子: const int I; 此时const仅仅修饰int 表明 I不是一个常量但是I的内容是常量。因为c/c++表达 对I的改变就是对I内容的改变所以 I也类似一个const。大家不妨可以用指针const修饰试试理解会有帮助的我想。
<3> 对于所有非const 类型可以无条件转化为 const类型,但是后者不能自动转化为前者除非显式的强制转化去掉const性。这样做是有意义的,因为const类型是非const的一个子集是一种特殊,由普遍转化为特殊是合理的,就象模板特化,继承的向上映射都是有意义的。
<4> 记住所有const修饰的内容并不是永远不可改变,如果人为的强制转化编译器是不会提醒的。因为它没有义务这么做,所以我们对其转化时要小心。
<5> 在const类成员函数处理时,我们引入了mutable修饰类成员变量,经过其修饰的成员变量可以在const类成员函数中被修改,编译器是允许的。而其他未被mutable修饰的成员还是按照const规则不能在const成员函数中被改变。
函数后面加“const”与不加是两个不同函数,如:
#include
using namespace std;
class A
{
public:
A(int i, int j){a = i; b = j;}
void print();
void print() const;
private:
int a, b;
};
void A::print()
{
cout << "hello!" << a << b << endl;
}
void A::print() const
{
cout << "hello const!" << a << b << endl;
}
int main()
{
A ss(3,6); // 定义A的对象时,没有用“const”
ss.print();
A const dd(20,2); // 定义A的对象时,用了“const”
dd.print();
}
posted @
2005-12-10 20:08 halCode 阅读(724) |
评论 (0) |
编辑 收藏
昨天去参加笔试,遇到了一题考计算机里存放的数据都是以原码、反码、还是补码的形式存放的。我还真的很久没有考虑过原码补码的问题了,不过凭他考这个问题,我可以猜出答案一定是补码了。虽然答案知道了,但是还真不知道还有这么一说,所以回来在网上搜了一篇这样的文章,才算是弄清楚是怎么一回事了:
数值有正负之分,计算机就用一个数的最高位存放符号(0为正,1为负).这就是机器数的原码了.假设机器能处理的位数为8.即字长为1byte,原码能表示数值的范围为
(-127~-0 +0~127)共256个.
有了数值的表示方法就可以对数进行算术运算.但是很快就发现用带符号位的原码进行乘除运算时结果正确,而在加减运算的时候就出现了问题,如下: 假设字长为8bits
( 1 ) 10- ( 1 )10 = ( 1 )10 + ( -1 )10 = ( 0 )10
(00000001)原 + (10000001)原 = (10000010)原 = ( -2 ) 显然不正确.
因为在两个整数的加法运算中是没有问题的,于是就发现问题出现在带符号位的负数身上,对除符号位外的其余各位逐位取反就产生了反码.反码的取值空间和原码相同且一一对应. 下面是反码的减法运算:
( 1 )10 - ( 1 ) 10= ( 1 ) 10+ ( -1 ) 10= ( 0 )10
(00000001) 反+ (11111110)反 = (11111111)反 = ( -0 ) 有问题.
( 1 )10 - ( 2)10 = ( 1 )10 + ( -2 )10 = ( -1 )10
(00000001) 反+ (11111101)反 = (11111110)反 = ( -1 ) 正确
问题出现在(+0)和(-0)上,在人们的计算概念中零是没有正负之分的.(印度人首先将零作为标记并放入运算之中,包含有零号的印度数学和十进制计数对人类文明的贡献极大).
于是就引入了补码概念. 负数的补码就是对反码加一,而正数不变,正数的原码反码补码是一样的.在补码中用(-128)代替了(-0),所以补码的表示范围为:
(-128~0~127)共256个.
注意:(-128)没有相对应的原码和反码, (-128) = (10000000) 补码的加减运算如下:
( 1 ) 10- ( 1 ) 10= ( 1 )10 + ( -1 )10 = ( 0 )10
(00000001)补 + (11111111)补 = (00000000)补 = ( 0 ) 正确
( 1 ) 10- ( 2) 10= ( 1 )10 + ( -2 )10 = ( -1 )10
(00000001) 补+ (11111110) 补= (11111111)补 = ( -1 ) 正确
所以补码的设计目的是:
⑴使符号位能与有效值部分一起参加运算,从而简化运算规则.
⑵使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计
所有这些转换都是在计算机的最底层进行的,而在我们使用的汇编、C等其他高级语言中使用的都是原码。看了上面这些大家应该对原码、反码、补码有了新的认识了吧!
下面总结一下:
1。正数的原码反码补码都相同,负数的反码是除符号位为1外,其他位全取反;补码就是反码+1
2。(10000000)补 规定为-128
3。计算机中的数据是以补码形式存储的
posted @
2005-12-09 19:32 halCode 阅读(7016) |
评论 (2) |
编辑 收藏
来上海近一个月了,几乎每天两点一线的来回跑着,现在,工作基本上已经做完,下午就买票回学校了。记得我还没有来上海时,心里是多么不情愿,不希望在这个寂寞的季节来到这个陌生的城市,我真的不愿孤独,虽然我会习惯于孤独。
工作交接完毕后,老板依然努力着说服我留下,我最终还是没有留下,因为我不得不回去找工作,我必须经历这一个过程,所以我下定决心回去了。但是在分别前的这一两天里,我发现我更多的是不舍。不知道我是习惯了这里一个人的生活,还是对这里我们一起吃饭、一起上班的人产生了友情。
我是个重情义的人,我会因为老板创业的艰辛而不去跟他计较报酬,不会对他提供给我的生活条件提出质疑,当然这些也不是特别的差。一个老同学跟我说:别指望在公司里跟老板产生什么真正的友情;还有人说:老板始终是会以自己公司的利益着想的。这些话的确有道理,即使老板真的把你当朋友,但是他经营着这个公司,他所有的生活和工作就是为了这个公司,所以他对友情的引导也不会脱离他公司的利益。我不认为这有多么自私,甚至不能用“自私”这个词来形容,发而我觉得,也许大多数人对友情的期望过于理想了,即使也许我就是其中之一。
下午就要走了,其实并不太想走,但也不意味着想留。整个人现在是矛盾的,对于以后的人生,越来越觉得压力太大。我以前都喜欢走一步算一步,这一次我很想从这种模式中摆脱出来,但是发现我仍没有实现。
不管怎样,票是买好了,火车是一定会开的。人能像火车一样吗?从一个起点,一直开到预定的终点!
posted @
2005-12-04 11:04 halCode 阅读(260) |
评论 (0) |
编辑 收藏
int型在16位、8位机上默认的是short int型,占2个字节,所以51单片机开发上的int类型都是2字节
在32位机上默认的是long int型,占4个字节,所以一般PC上int类型都是4字节
指针类型所占空间不会因为所指变量类型的不同而不同,在16位8位机上都是2字节;在32位机上都是4字节,如char *a、int *b, sizeof(a)、sizeof(b)全部都等于4
signed char 类型的取值范围是 -128~127
posted @
2005-11-26 10:33 halCode 阅读(325) |
评论 (0) |
编辑 收藏
从来没有独立做过ODBC数据库的程序,今天才发现原来自己动起手来是那么得蹒跚,呵呵。看了《
Visual C++中为普通程序添加ODBC应用》后收获不小,现把这些记录下来,以便日后再忘记的话可以查阅^_^#
1。给程序加入ODBC数据库的支持需要用到两个类:CDatabase和CRecordset,主要是后面一个;
2。一般步骤为:
(1) 创建一个继承于CRecordset的类CMyRS,系统会自动提示你选择数据源,并会自动关联数据表中各项属性
(2)在需要查询数据库的地方先construct一个CMyRS类的实例myRS,然后调用myRS.Open()打开记录集
(3)移动数据集指针到需要的地方,从CMyRS中系统自动关联好的数据表各项属性的变量中读取相应的值
3。需要注意的是:
(1)调用myRS.Open()前
一定要先construct CMyRS类的对象,构造的时候可以事先创建一个CDatabase类的对象,然后将该对象的指针传给构CMyRS的造函数,如:CMyRs myRS(&db); 如果为空的话,当调用myRS.Open()时,系统会自动为myRS构造一个CDatabase的对象,并且调用CMyRS类的Default SQL 和CONNECT字符串来连接数据源。所以不用担心没有连接数据库数据源。
(2)如果事先创建了一个CDatabase的对象db,则可以先用自己的conn连接字和sql连接字Open它,然后传给CMyRS的构造函数,构造的myRS再不用任何参数Open()就可以了
可能有些地方理解的还是不对,希望随着以后多接触再来修改!
posted @
2005-11-24 16:47 halCode 阅读(434) |
评论 (1) |
编辑 收藏
qt对国际化有很好的支持。但默认的是unicode编码。中文系统下默认的并非unicode,
而是比如gbk或gb2312。所以在进行const char*参数传递和显示时必须特别注意。
比如在默认情况下
QMessageBox::information(this, "Test", "这是一个测试");
中文字符无法正确显式
又如
bool connect(const char * connectString);
你如果输入
QString str("一个测试");
connect((const char*)str);
默认是调用QString.latin1()方法,是直接从Unicode的QString返回latin-1字符表示
集。在中文系统下有时不是你想要的。
解决方案:在main.cpp里增加
QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());
这时涉及到QString/QCString到const char*的转换将使用本地的编码集。
类似的还有setCodecForTr()方法。
NOTE: 这跟qt使用unicode进行内部通讯、显示并不冲突。当显示一个const char*时,
qt会将const char*再行转成unicode。
另一种麻烦点的方法:
在写QT程序的时候,怎样使用中文?QT内建了国际化支持,可以使用国际化支持来实现。但,比较复烦琐,那怎么简单地使用中文呢?
QT 的QString内部是使用Unicode编码的,在写源码的时候,可以使用本地的GB2312/GBK/GB18030,或者UTF8编码。如果是使用前者的话,那可以使用QString::fromLocal8Bit("本地中文字符串")来得到想要的结果。如果是使用后者的话,可以使用 QString::fromUtf8("UTF8编码格式的中文字符串")来得到想要的结果。
posted @
2005-11-23 17:54 halCode 阅读(5253) |
评论 (0) |
编辑 收藏
1. QT和VC目前最大的不同就是消息的管理
VC的不同对象之间发送消息是对象A发送一个消息给对象B就不管了,至于B对于此消息该什么响应函数来处理,由对象B自己定义的消息处理函数来响应;
而QT中,必须有一个平台来管理A-->B这个过程,它需要知道A发生了什么消息(signals),传给B后,还要通知B用什么消息处理函数(slots)来处理。
2. 在有自定义消息处理的类中,必须用这样的结构
Q_OBJECT //这种signal-slot结构必须使用的宏
public slots:
signals:
3. 当一个.h文件中申明一个类的变量,而这个类已经在其他文件中定义好了时,可以只把这个类的头文件只包含在该.h文件对应的.cpp文件中,而在该.h文件中只需要用一句class ClassName再申明一次就可以了,这样可以提高编译速度
4. 在头文件中可以用下列一组宏来防止该头文件被包含多次:(具体用法还要再查查)
#ifndef LCDRANGE_H
#define LCDRANGE_H
. //头文件内容开始
#endif
posted @
2005-11-21 15:44 halCode 阅读(517) |
评论 (0) |
编辑 收藏
#include <QApplication>
#include <QFont>
#include <QPushButton>
#include <QWidget>
class QMyWidget : public QWidget
{
public:
QMyWidget(QWidget *parent = NULL);
};
QMyWidget::QMyWidget(QWidget *parent)
: QWidget(parent)
{
setFixedSize(200, 200);
QPushButton *quit = new QPushButton("Quit", this);
quit->setGeometry(10, 40, 180, 40);
quit->setFont(QFont("宋体", 18, QFont::Bold));
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMyWidget myWidget;
myWidget.show();
return app.exec();
} 注意:
1。定义一个类时用class关键字,定义完后不要忘记这时一个语句,需要用
分号结束。
2。Qt成员函数的变量命名规则是小写开头、大写间隔,与VC中的不一样。
3。好久没有用C++发现好多语法都生疏了,唉,不行了,要赶紧捡起来, ^_^#!
posted @
2005-11-17 14:24 halCode 阅读(765) |
评论 (1) |
编辑 收藏
明天
就像是
盒子里的
巧克力
糖!
什么滋味,充满想像!
第一次听4INLOVE的《一千零一个愿望》就被这优美的旋律吸引了,几位纯真可爱的小女生将我带到了快乐的童年,让我情不自禁无边地幻想起童年的未来。想一想,自己都忍不住想笑了!
今天,突然看到了里面的这句歌词,突然有种悸动的感觉,我的明天,到底在哪里?
我猜这句歌词来自于经典电影《阿甘正传》中阿甘的那句经典对白:Mom said, life is like a box of chocolates, you never know what you'll gonna get! 很可惜,我没有看过这部电影,只是听过这句话的解释,所以,我并不能真正知道我需要学习阿甘怎样的精神。有时候,我就觉得我跟我所想象的阿甘有90%的相似:老天不公,只有10%的不同:我没有他那种勇敢和执着。我也常常抱怨我所不能改变的现实,我也常常告诉自己要努力去改变我能改变的事实,但是到头来,我仍没有找到我所希望的我,其实我要求不高,真的;可是也许我努力的也不够,可能也是真的!
我的明天在哪里,我的明天是什么滋味?我不可避免的走到这一步,可是我却还没有做好拆开巧克力盒子的准备!所以,我很害怕!不仅仅害怕我的巧克力不知道是什么滋味,更害怕我仍然不敢拆开巧克力盒子。
我真的该准备了,我必须面对,不要害怕拆开里面的巧克力。我有我的愿望,我有我的明天,我不愿意再停留在昨天了!!
posted @
2005-11-13 16:02 halCode 阅读(466) |
评论 (0) |
编辑 收藏