我自己记录的C++笔记

一.关于New.试验环境.
    1.建一个 C++ Win32 程序 (win32Con).
    2.新建一个 .h 头文件.在里面写下列类.
        class Dat
        {
        private:
            double m_Len;
        public:
            Dat()
            {
                m_Len=0;
            }
            Dat(int len)
            {
                m_Len=len;
            }
        };
    3.在 win32Con.cpp 文件中声明该类.现在分析声明类的方法,一般声明两种类型,声明一个指针和一个对象.如:
        Dat*    d1=new    Dat();        //声明指针.
        Dat        d2=Dat();            //声明对象.
       
        如此看来,两者的声明是有区别的. new 声明后返回的是一个指针吗? 用 sizeof() 试试!
       
        std::cout<<sizeof(d1)<<endl;    //输出 4    ,看来 new 返回的确实是一个指针.
        std::cout<<sizeof(d2)<<endl;    //输出 8    ,对象返回了一个对象的实体.
       
        那在 Windows 系统对象(像 内核对象 thread , Process , file 都返回 handle )大小大多数都是4位的,那它们都是指针吗?
        看 Windows 的 WinDef.h 文件.随便找一个简单的吧.
        typedef struct tagSIZE
        {
            LONG        cx;
            LONG        cy;
        } SIZE, *PSIZE, *LPSIZE;
           
        大都是这种结构.其中 最常用的是 PSIZE 和 LPSIZE .声明类的方法都是一样的.
        SIZE*    s1=new    SIZE();        //声明指针.
        SIZE    s2=SIZE();            //声明对象.
       
        这就是 Windows 的方法.所以如果用 new 关键字,必定返回一个指针.
    4.在复制构造函数 Dat(Dat & D) 中,Dat一定要用引用类型.这是因为,只有在复制构造函数中,才能使用引用类型的私有变量.如
        Dat(Dat & D)
        {
            m_Len=D.m_Len;        //本来m_Len是私有变量,为什么可以在这可以被引用呢?
        }
   
        引用实际上就是变量的别名,这里有几条规则:
        声明变量时必须初始化
        一经初始化,引用不能在指向其它变量。
        任何对引用的改变都将改变原变量。
        引用和变量本身指向同一内存地址。
   
        用const修饰引用,使应用不可修改,但这并不耽误引用反映任何对变量的修改。
   
        那么,在函数返回 引用类型时,返回的引用如何使用呢?

二.函数调用的问题.
1.在函数调用中,被调函数的参数是重新构造的.所以,在下列调用中,不会成功.
    void GetMem(char * pchr)        //在这里,相当于:    void GetMem()
    {                        //    {
        pchr=(char *)malloc(100);        //        char * pchr=chr;    //该处的chr是main中的chr.    但两个变量指向的是不同的内存地址.
    }                        //        pchr=(char*)malloc(100);    }
    void main()
    {
        char * chr=NULL;
        GetMem (chr);        //这样调用的话,在GetMem中有一次参数重构.
        strcpy(chr,"abc");
        cout<<chr<<endl;
    }
    以上相当于这样写:
    void main()
    {
        char * chr=NULL;
        char * pchr=chr;    //@@@后注.
        pchr=(char *) malloc(100);
        strcpy(chr,"abc");
        cout<<chr<<endl;
    }
    @@@:
    两个变量 chr , pchr 所在的内存是不同的.所在内存的内容是一个内存地址. 这里的赋值是说,使两个变量所在内存的内容相同.我们的目的是想给两个变量都配同一块内存.所以 (char *) malloc(100) 应该指向两个变量所在内存的内容(是一个地址,也就相当于 &chr 或 &pchr).但是给内存地址赋值是不允许的.所以程序应该修改如下:
    void main()
    {
        char * chr=NULL;
        char ** pchr=&chr;    //这就行了.
        *pchr=(char *) malloc(100);
        strcpy(chr,"abc");
        cout<<chr<<endl;
    }
2.函数调用的另一个问题.
    char* GetMem(void)
    {
        char * pchr=(char*)malloc(100);
        return pchr;
    }
    void main()
    {
        char * chr=GetMem();
        strcpy(chr,"abc");
        cout<<chr<<endl;
    }
    这样调用是成功的.为什么呢?该函数可以变化成如下形式.
    void main()
    {
        char * chr =NULL;
        char *p=(char*)malloc(100);
        chr=p;        //赋值的是两个变量所指向的内容(其实是一个地址).
        free(p);    //释放 p 所指向的地址.也就是说,经过 free(p); 后, p 就没有指向任何地址了.但是该变量是存在的.可以把它重新指向一个新的地址,并分配空间.
        strcpy(chr,"abc");
        cout<<chr<<endl;
    }
3.函数调用的另一个问题.
    void func(char[24] chr)
    {
        cout<<sizeof(chr)<<endl;
    }
    void main()
    {
        char * c="hello word!";
        func(c);
    }
    //该程序会输出 4
4.在程序中所有声明的指针变量,均指向一个默认的地址.所以,在程序中所有声明的变量,都有相同的默认初始值.
    所有变量定义后,都会指向一个地址.不能判断它是否已经初始化.
    void main()
    {
        int *l;
        int *k;                //它们指向同一个地址.
        cout<<l<<endl;
        cout<<k<<endl;
       
        int i1;
        int i2;
        cout<<i1<<endl;
        cout<<i2<<endl;        //返回同一个值.
    }
三 API函数笔记.


十一.操作系统和编程环境设置:
    1.设大硬盘Cache
        BT会多线程地下载和上传,很多数据吞吐,Windows默认只有512KB的Cache显然不够,如果内存在256MB以上,开大一些Cache应该可以减少硬盘读写,提高性能。一般设在8-16MB效果最好。我设到32MB,开4个BT硬盘灯都不怎么闪。
        a) 运行 "regedit";
         b)去[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\IoPageLockLimit];
         c) 根据你的内存修改其十六进制值:
           8000为32MB,4000为16MB,其他数字按此计算。
        补充计算转换方法如下:
        1MB = 1024K,
        10MB = 10240K
        = 2800(16进制)
        = 2*16^3 + 8*16^2 + 0*16^1 + 0*16^0 = 10240k (十进制)
         d) 重启
        如果没有找到IoPageLockLimit,就要新建,类型为DWord。


    2.Windows 2000/XP/2003在默认情况下采用缩略图功能,但通过设置即可禁止在所有的图片文件夹中自动生成“Thumbs.db”文件:在“控制面板”中双击“文件夹选项”,在“文件夹选项”对话框中切换到“查看”标签,在“不缓存缩略图”复选框前打上“√”(如图),再点击“确定”按钮退出即可。
    3.显示在列出成员的注释中
        在C#.NET中类,属性,方法前面用///进行标记可做为注释,
        而在C++中类在前面用//进行注释,属性,方法在后面用//进行注释.
十二.C++基础.
    1. sizeof() 的问题.
        char s1[256];
        printf("%d\n",sizeof(s1));    //输出256
        char *s2=new char[256];
        printf("%d\n",sizeof(s2));    //输出4
        printf("%d\n",sizeof(*s2));    //输出1
    2.如何求得数组的长度.如
        char* str=new char[1024];     //如何求得1024. strlen(str)-1
        float * f=new float[12];    //如何求得 12.
    3.关于指针与引用.
        float * f=new float;
        *f=13;
        cout<<*f<<endl;
        f=new float[12];
        cout<<*f<<endl;
    4. const throw() 的用法.
    5. const 的用法.
        1. const c    这种写法是定义一个常数,其默认是 const int c;
        2. const char * c 这种写法是定义一个不可变的恒量
        3. const char  * const  c 和                 const char  const * const c="hello";
        4. 当你定义一个不修改变量的成员函数时,定义它为一个const成员函数是一个很好的办法,有两个好处:
            1,可以保证这个函数的安全使用,因为它不改变变量的状态,比如,它不能给变量赋新值,不能分配内存或者激活析构函数.
            2,提高程序的可读性:即使没有看到源代码,用户也可以明确此函数的实现目的.
            一个例子:(one declaration and one definition of const member function shown):
             
            class Person {
                    int age;
                    long social_security_n;
                    ...
                    //改变变量状态
   
                    void setAge (int Age);
                    void setID(long ssn) { social_security_n = ssn; }
   
                    //访问变量,不能改变
   
                    int getAge () const; //不能修改变量
                    long getSocial_security_n () const {return social_security_n;}
            };
    6.    public virtual 和 private virtual 的区别.
        关于C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,现将本人的一些体会总结如下,期望对大家有所帮助:
         一 const基础
            如果const关键字不涉及到指针,我们很好理解,下面是涉及到指针的情况:
            int b = 500;
            const int* a = &b;             [1]
            int const *a = &b;            [2]
            int* const a = &b;            [3]
            const int* const a = &b;    [4]
            如果你能区分出上述四种情况,那么,恭喜你,你已经迈出了可喜的一步。不知道,也没关系,我们可以参考《Effective c++》Item21上的做法,如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如不能*a = 3 ;[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;[4]为指针本身和指向的内容均为常量。
            另外const 的一些强大的功能在于它在函数声明中的应用。在一个函数声明中,const 可以修饰函数的返回值,或某个参数;对于成员函数,还可以修饰是整个函数。有如下几种情况,以下会逐渐的说明用法:A& operator=(const A& a);
            void fun0(const A* a );
            void fun1( ) const;    // fun1( ) 为类成员函数
            const A fun2( );

        二 const的初始化
            先看一下const变量初始化的情况
            1) 非指针const常量初始化的情况:A b;
            const A a = b;
   
            2) 指针(引用)const常量初始化的情况:A* d = new A();
                const A* c = d;
            或者:const A* c = new A();
            引用:
                A f;
                const A& e = f;   // 这样作e只能访问声明为const的函数,而不能访问一般的成员函数;

            [思考1]: 以下的这种赋值方法正确吗?
            const A* c=new A();
            A* e = c;
            [思考2]: 以下的这种赋值方法正确吗?
            A* const c = new A();
            A* b = c;

        三 作为参数和返回值的const修饰符

            其实,不论是参数还是返回值,道理都是一样的,参数传入时候和函数返回的时候,初始化const变量
            1 修饰参数的const,如 void fun0(const A* a ); void fun1(const A& a);
            调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为const A* a,则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;如形参为const A& a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。
            [注意]:参数const通常用于参数为指针或引用的情况;
            2 修饰返回值的const,如const A fun2( ); const A* fun3( );
            这样声明了返回值后,const按照"修饰原则"进行修饰,起到相应的保护作用。const Rational operator*(const Rational& lhs, const Rational& rhs)
            {
            return Rational(lhs.numerator() * rhs.numerator(),
            lhs.denominator() * rhs.denominator());
            }
   
            返回值用const修饰可以防止允许这样的操作发生:Rational a,b;
            Radional c;
            (a*b) = c;
   
            一般用const修饰返回值为对象本身(非引用和指针)的情况多用于二目操作符重载函数并产生新对象的时候。
            [总结] 一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。
            原因如下:
            如果返回值为某个对象为const(const A test = A 实例)或某个对象的引用为const(const A& test = A实例) ,则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。
   
            [思考3]: 这样定义赋值操作符重载函数可以吗?
            const A& operator=(const A& a);

        四 类成员函数中const的使用

            一般放在函数体后,形如:void fun() const;
            如果一个成员函数的不会修改数据成员,那么最好将其声明为const,因为const成员函数中不允许对数据成员进行修改,如果修改,编译器将报错,这大大提高了程序的健壮性。
            五 使用const的一些建议
   
            1 要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;
            2 要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;
            3 在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;
            4 const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;
            5 不要轻易的将函数的返回值类型定为const;
            6除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;
   
   
            本人水平有限,欢迎批评指正,可以联系 kangjd@epri.ac.cn
   
   
            [思考题答案]
            1 这种方法不正确,因为声明指针的目的是为了对其指向的内容进行改变,而声明的指针e指向的是一个常量,所以不正确;
            2 这种方法正确,因为声明指针所指向的内容可变;
            3 这种做法不正确;
            在const A::operator=(const A& a)中,参数列表中的const的用法正确,而当这样连续赋值的时侯,问题就出现了:
            A a,b,c:
            (a=b)=c;
            因为a.operator=(b)的返回值是对a的const引用,不能再将c赋值给const常量。

    6. 如何捕获异常.当异常出现后,如何捕获所在的行?
    7. #define 和 #typedef 有何区别.
        #define 一个别名 后面跟一串文字 再跟一串文字
        typedef 一串文字 再跟一串文字 最后是一个别名    ,最后加分号.
    8.    字符型如何转换到Int , 如 int i = (int)"2"; (不行的.)如果是 BSTR转换到Int呢?
十二,一些想法
    在破解 WinRar 密码的过程中, WinRar 的Dll ,我想是经过加壳处理的。用 OleView.exe 打不开 Dll
    所以,只能用 暴力破解的方法了。用 VC 去发送消息。获取结果。
    为了长时间运行。应该选择在计算机闲时运行。并且,记录运行的时刻。

posted @ 2009-03-09 00:51  NewSea  阅读(295)  评论(0)    收藏  举报