首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • 高手请进-->深入C++初始化的艺术。。。。。。。。。。。。。。
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • chonganget
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 揭贴率:
    发表于:2008-08-21 17:46:18 楼主
    最近一直为C++中的初始化迷惑,在网上也找了不少的贴子,但还是感觉还是不够?还请高手指点,首先,能从语音上很好的分析,然后再深入底层的实现,结合具有体的实例展现初始化的具体细节,体现C++的编程思想?
    下面是一些网上的贴子,和大家分享,同时希望高手们深思????以给入门者学习?


    C++经过这么多年的发展,已然成了一种文化和艺术,而这种艺术和文化并不是C++所固有的,是C++在各个方面的应用的总结和艺术化的结果。C++看起来比较复杂,但是深入其中你会发现C++是那么优美而富有哲学感。为了使C++更艺术化,C++语言大师们都为此而付出甚多,他们都在追求简单,追求编程的艺术。
    几乎所有的编程语言都有这样或那样的初始化方法,比较新的语言如C#就将很多的初始化技术都集成到编译器里面去了,而很多编程语言都需要程序员用特定的方法去实现。C++的初始化技术很大程度上就依赖于程序员。本文介绍了几种常见的、实用的初始化技术。
    1. 编译期初始化
    所谓的编译期初始化,指的是符号的值在编译期就可以确定下来,一般包括普通常量的初始化和已经利用模板技术构造常量的初始化技术。
    1.1. 常量
    如const int Scale = 1;
    enum ColorSpace{RGBColorSpace,CMYKColorSpace};
    class Example{
    static const int Count = 1;
    }
    1.2. 利用模板
    这是模板元编程实用到的一个最基本的技术。这种技术利用编译器对模板进行递归编译的机理来实现某个常量的初始化。如:
    template factorial;
    template < > factorial <1>{enum {result=1};};
    template < > factorial{enum {result=N* factorial ::result};};
    2. 静态初始化
    所谓的静态初始化,指的是程序启动的时候初始化全局(静态)变量或静态成员编程的行为。
    2.1. 全局变量初始化
    如int g_globalCount = 1;
    static int g_s_globalCount = 1;
    2.2. 静态成员变量的初始化
    如class Example{
    static Example NullExample;
    }
    Example Example::NullExample;
    3. 动态初始化
    这种初始化技术利用了类的构造和析构函数的基本特性。
    如我们需要在程序启动的时候注册某个类的创建函数到类工厂,我们可以按照下面的方式进行做:
    /////////////////////////////////////定义初始化所需要的宏等
    typedef Geometry* (*CreateFuncPtr)();
    struct auto_register{
    auto_register(CreateFuncPtr func){//注册}
    ~auto_register(){//取消注册}
    };
    #define AUTO_REGISTER(class_name)\
    static const auto_register _register## class_name ##( class_name::CreateGeometry);
    //////////////////////////////////定义基于上面的初始化技术的实现
    class Geometry{
    public: static Geometry* CreateGeometry(){…}
    }
    class DiamondGeometry{
    public: static DiamondGeometry* CreateGeometry(){…}
    }
    AUTO_REGISTER(DiamondGeometry)
    class RectangleGeometry{
    public: static RectangleGeometry* CreateGeometry(){…}
    }
    AUTO_REGISTER(RectangleGeometry)

    来自实际项目的一段代码,简化形式如下:
    switch (t)
    {
    case 0:
      int a = 0;
      break;
    default:
      break;
    }
        有什么问题吗?似乎没有。请用编译器编译一下……
        嗯?!一个错误“error C2361: initialization of 'a' is skipped by 'default' label”。这怎么可能?
        几番思琢,悟出解释:C++约定,在块语句中,对象的作用域从对象的声明语句开始直到块语句的结束,也就是说default标号后的语句是可以使用对象a的。如果程序执行时从switch处跳到default处,就会导致对象a没有被正确地初始化。确保对象的初始化可是C++的重要设计哲学,所以编译器会很严格地检查这种违例情况,像上述的示例代码中default语句后面并没有使用a,但考虑到以后代码的改动可能无意中使用,所以一样被封杀。
        明白了原因,解决起来就很容易了。只要明确地限制对象a的作用域就行了。
    switch (t)
    {
    case 0:
      {  //added for fix problem
      int a = 0;
      break;
      }  //added for fix problem
    default:
      break;
    }
        如果确实需要在整个switch语句中使用对象a,那就把int a = 0;移到switch语句之前即可。不过从原先的语句看,其意图似乎并不是这样的,所以推荐前面的解决方案。

        结束了吗?没有。让我们继续考究错误提示信息中“initialization”(也就是初始化)的确切含义。C++很看重初始化,所以往往会给我们造成一种错觉,似乎对象在定义处一定会经过初始化过程。真实情况如何呢?还是用实例来证明吧。
    switch (t)
    {
    case 0:
      int a;
      a = 0;
      break;
    default:
      break;
    }
        编译,这次没有报错。很明显int a;定义了对象,但没有进行初始化,否则就应该报告原先的错误。
        再看看用户自定义类型。
    class B
    {
    };
    switch (t)
    {
    case 0:
      B b;
      break;
    default:
      break;
    }
        编译结果也没有错误,所以没有提供构造器的类仍然没有初始化过程。
        如果给类加入构造器,情况就不同了。
    class B
    {
    public:  //added for initialization
      B(){} //added for initialization
    };
        这样就能重现原先的错误。证明有了构造器,编译器就将进行初始化处理并对之进行安全检查。

        从上面的实验,可以直观地体验到一些基本的C++观念和原理,并提高认识深度。
        1.int a = 0;既是声明也是定义,还包括初始化;int a;是声明还是定义依上下文而定,但如果是定义就不会包括初始化;a = 0;仅仅是赋值语句,在此句前对象已经存在了。
        2.为了避免不必要的开销,默认情况下,即程序员没有在代码中明确指示时,编译器不提供初始化过程。某些需要确保初始化的类,请提供构造器。这里透露出一个C++的设计哲学:通常你会面对多种选择,所以请精确地控制代码,其收益则是可以自由取舍调配的安全性、速度、内存开销等程序特性。
        3.严密注意程序中标号的使用情况,特别是case、default等常规标号,否则他们可能会破坏对象的正确状态。如果提供了对象初始化,则能够获得编译器的额外帮助。
    注意:如有侵权,敬请告之,必删掉!!!
    20  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • synix521
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 17:51:471楼 得分:0
    不是高手,先Mark
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • Who_know_me
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 17:54:522楼 得分:0
    研究研究~~
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • yshuise
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 17:57:583楼 得分:0
    楼主有一种重要的初始化没有讲:RALL
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • chonganget
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 18:17:214楼 得分:0
    那还有一个没写上就是类成员中的static成员变量声明时不能初始化,那什么static const int val = 10;这样的类成员却可以在类声明中初始化,书上一直说这是一种特例,可是我想知道最本质的解释,为什么C++标准中要有这样一种特例,我想一定有它的道理?就是我不知道而矣。。。。还请大家讨论?
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • baihacker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 3

    发表于:2008-08-21 19:03:475楼 得分:0
    引用 4 楼 chonganget 的回复:
    那还有一个没写上就是类成员中的static成员变量声明时不能初始化,那什么static const int val = 10;这样的类成员却可以在类声明中初始化,书上一直说这是一种特例,可是我想知道最本质的解释,为什么C++标准中要有这样一种特例,我想一定有它的道理?就是我不知道而矣。。。。还请大家讨论?

    有贴子讨论过的。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • ttzzgg_80713
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 19:24:406楼 得分:0
    比较无聊的玩意,折腾编译器
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • chonganget
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 20:49:587楼 得分:0
    下面是我能收到的答案,但是我想问为什么?
      作为特例有序型的const  静态数据成员可以在类体中用一常量值初始化。一般地静态数据成员在该类定义之外被初始化如同一个成员函数被定义在类定义之 
      外一样在这种定义中的静态成员的名字必须被其类名限定修饰例如下面是interestRate 
      的初始化 
      //  静态类成员的显式初始化 
      #include  "account.h" 
      double  Account::_interestRate  =  0.0589; 
      与全局对象一样对于静态数据成员在程序中也只能提供一个定义这意味着静态 
      数据成员的初始化不应该被放在头文件中而应该放在含有类的非inline  函数定义的文件中 
      静态数据成员可以被声明为任意类型它们可以是const  对象数组或类对象等等例如 
      #include  <string> 
      class  Account  { 
      //  ... 
      private: 
      static  const  string  name; 
      }; 
      const  string  Account::name(  "Savings  Account"  ); 
      作为特例有序型的const  静态数据成员可以在类体中用一常量值初始化例如如果 
      决定用一个字符数组而不是string  来存储账户的姓名那么我们可以用int  型的const  数据成 
      员指定该数组的长度例如 
      //  头文件 
      class  Account  { 
      //  ... 
      private: 
      static  const  int  nameSize  =  16; 
      static  const  char  name[nameSize]; 
      }; 
      //  文本文件 
      const  int  Account::nameSize;  //  必需的成员定义 
      const  char  Account::name[nameSize]  =  "Savings  Account"; 
      关于这个特例有一些有趣的事情值得注意用常量值作初始化的有序类型的const  静 
      态数据成员是一个常量表达式constant  expression  如果需要在类体中使用这个被命名的 
      值那么类设计者可声明这样的静态数据成员例如因为const  静态数据成员nameSize 
      是一个常量表达式所以类的设计者可以用它来指定数组数据成员name  的长度 
      在类体内初始化一个const  静态数据成员时该成员必须仍然要被定义在类定义之外 
      但是因为这个静态数据成员的初始值是在类体中指定的所以在类定义之外的定义不能指 
      定初始值 
      因为name  是一个数组不是有序类型所以它不能在类体内被初始化任何试图这 
      么做的行为都会导致编译时刻错误例如 
      class  Account  { 
      //  ... 
      private: 
      static  const  int  nameSize  =  16;  //  ok:  有序类型 
      static  const  char  name[nameSize]  = 
      "Savings  Account";  //  错误 
      }; 
      name  必须在类定义之外被初始化 
      这个例子还说明了一点我们注意到成员nameSize  指定了数组name  的长度而数组name 
      的定义出现在类定义之外 
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • buzhiyao
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 21:49:278楼 得分:0
    mark
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • matrixdwy
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 21:56:249楼 得分:0
    引用 3 楼 yshuise 的回复:
    楼主有一种重要的初始化没有讲:RALL

    兄弟,是RAII吧,resource acquisition is initialization
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • lp3331
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 22:01:3210楼 得分:0
    mark~
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • jiazhh_love
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 22:24:4511楼 得分:0
    mark
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zhangxichao
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 22:30:2612楼 得分:0
    mark,zan yi ge
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • richbirdandy
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-21 22:43:5513楼 得分:0
    up了 排版不好
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • guowei1651
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-22 21:17:0714楼 得分:0
    你如果用的是vc的话可能不支持一些标准  所以还是用g++吧
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • fangbing007
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-22 23:48:4415楼 得分:0
    学习,收藏中!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • pengzhixi
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-23 01:18:1216楼 得分:0
    mark
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • iambic
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 4

      3

      3

    发表于:2008-08-23 02:34:0217楼 得分:0
    你的问题很长。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • Silitex
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-23 09:00:3518楼 得分:0
    mark
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • Vegertar
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-23 09:10:0719楼 得分:0
    mark
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • bxx5203344
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-23 16:10:2520楼 得分:0

    mark
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • Fishest
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-23 17:31:2121楼 得分:0
    mark
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • lili1
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-25 16:30:4022楼 得分:0
    没什么兴趣。
    也不知道类的构造函数的如下的初始化方法说了没有?

    class TClassName
    {
    private:
        int a; 
        int b;                           
    public: 
        TClassName();     
    };

    TClassName::TClassName():a(0),b(1) //初始化a为0 ,b 为1 
    {
        cout < <a < <b < <endl;                                     
    }       
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • lxb_champagne
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-25 17:05:5023楼 得分:0
    顶起来。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • sunny50
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-08-25 17:36:1124楼 得分:0
    前几天还刚刚遇到switch case那个问题,只知道怎么修改,但不知道原因,现在我明白了,谢谢!
    修改 删除 举报 引用 回复

    网站简介广告服务网站地图帮助联系方式诚聘英才English 问题报告
    北京创新乐知广告有限公司 版权所有 京 ICP 证 070598 号
    世纪乐知(北京)网络技术有限公司 提供技术支持
    Copyright © 2000-2008, CSDN.NET, All Rights Reserved