博文

全局范围的语句(2006-10-24 13:29:00)

摘要:最近在学VC++,看那本《深入浅出MFC第2版》。看到第三章,有个模拟RTTI的程序。我看懂后自己编写代码。也像书上一样定义了一大堆的宏,基本上都没什么大问题,除了在一条语句“CCObject::classCCObject.Next = NULL;”上卡壳了。 因为这条语句是在宏定义IMPELEMENT_DYNAMIC(class_name)中,而IMPLEMENT_DYNAMIC的执行是在main之前,也是全局范围中。编译器给我的错误提示是:在"."之前少个";",还有CCObject::classCCObject缺少类型说明。我看那条语句,看了又看,心想“妈的!不就一个类的一个静态对象中的成员变量赋值吗?怎么会错呢?” 于是开始了痛苦的调错经历:。。。。。(省略掉)真是郁闷死我了!! 最后发现:这条语句在预处理展开后是放在全局范围内,全局范围只能声明和定义,不能执行语句。想想真是废话,全局范围的语句给谁执行呢? 然后再看书上的解决方法,作者用的是使用一个只含有构造函数的类声明,然后定义一个这样的类,以需要注册的类的名字为参数进行构造。(详情见原书)
当初看到他的处理方法我觉得真是多此一举,直接执行不就行了吗?现在才发现作者的高明之处。自己水平的烂~~ 上面是写给自己看的,用来记住这件事情。我平时写博客都希望能给别人一些信息,来解决和我有一样苦恼的人的烦忧。我平时有问题也用搜索引擎,有的人的博客确实给了我不少帮助。 那么啰嗦其实就是:全局范围不能执行语句,要想执行,调用类的构造方法~~......

阅读全文(2273) | 评论:0

C++中的内存分配 memory management(2006-09-29 12:28:00)

摘要:很早之前一直遗留的问题终于在今天得以解决。 程序在运行时需要的内存通过下面3种方法获得: 一、全局变量(包括静态局部变量等):在程序运行之前在静态内存空间分配。它们的生命周期是整个程序的运行过程。
2006-11-14     16:15 补充:
若在函数f()中定义一个静态变量a,则a在f()被调用的时候构造,在程序退出时被析构。 二、局部变量(包含在{}中):在栈(stack)中分配。
函数的调用过程(函数调用时的参数、函数返回地址、函数返回值、函数体内的其它变量等如何在栈中进行处理)现在还不是很懂,过段时间再来补充。
2006-11-14     16:27 补充:
函数在被调用时,首先将其参数压入栈中,标准为逆序(即从右向左压入);然后将函数的返回值地址压入;最后是函数内部的局部变量。当函数要返回(return)时,弹出所有局部变量,之后(1)C语言中把返回值压到返回地址的顶部;(2)而C++中返回值在寄存器里,直接写入返回值地址中,这样就可以避免中断之类所造成的返回值丢失的问题。 三、运行时对象:在堆(heap)中分配,必须手动释放内存空间。
(1)  生存周期:如果你不手动释放,则一直持续到程序结束;
(2)  void指针:如果将开辟的空间地址赋给一个void指针,它能记住这个空间的大小,当delete它时它能正确地释放这个大小的空间,与释放非void指针唯一不同的是它不调用析构方法;
(3)  动态对象数组:当动态定义一个对象数组时,这个数组内的所而对象都调用了它们各自的构造方法,A* ap = new A[100]; 在析构这个数组时,如果是delete []ap,则调用数组内所有对象的析构方法,并释放这100个对象所占的空间;如果是delete ap,则只调用数组内的第一个对象的析构方法,然后释放整个数组占用的空间(在试验时用这种释放空间的方法在调用第一个对象的析构方法、准备释放空间时会出现错误,所以要释放数组时就应采取第一种方式)。......

阅读全文(3404) | 评论:0

static const in VC++(2006-09-13 09:39:00)

摘要:有一条语句:static const number = 100; 这条语句放置在C++中的类中应该是没问题的,在C++标准中它表示编译时就能产生值,可以用在如数组定义等编译时执行的语句中。 但是,有些编译器并不完全支持C++标准,如VC++ 6.0。于是有替代方法如下: class A {         enum { number = 100 }; //在编译时产生值        int a[number]; //编译时执行的数组定义 };......

阅读全文(2606) | 评论:0

Temporaries(2006-09-12 15:10:00)

摘要:临时变量(Temporaries)是编译器在计算表达式时所构造的变量。它与普通的对象相同,只是它由编译器控制,而不受程序员的控制而已。 临时对象在产生时并不调用构造函数,但在销毁时会调用析构函数。我个人的理解是:临时对象是对已有对象的复制,不会产生无效值,因为已有对象已经调用过构造函数了。为了效率,临时对象没有必要再调用一次构造函数。但析构不同,必须调用以释放一些资源。
补充:临时对象调用的是复制构造方法A(const A&),A为类名。 书上说临时变量应该是常量(const型),但好像并不是如此。或许常量只是一个建议,但并不一定实行。 class X{}; X f() {return X()} void g1(X&) {} void g2(const X&){} main() {        g1(f()); //书上说会编译错误,但我在VC上通过编译,且没有警告        g2(f()); //成功 }......

阅读全文(2149) | 评论:0