Chinaunix首页 | 论坛 | 博客
  • 博客访问: 60322
  • 博文数量: 15
  • 博客积分: 517
  • 博客等级: 一等列兵
  • 技术积分: 230
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-14 09:54
文章分类

全部博文(15)

文章存档

2012年(15)

c++

分类:

2012-04-14 10:02:01

1、为了避免程序运行完毕后自动关闭窗口,可以通过cin.get()让窗口一直打开,直到用户按下enter键为止。
2、名空间,如果使 用#include 而不是则应使用using namespace std名空间编译指令来使iostream中的定义对程序可用。名空间能让各厂商能够将其产品封装在一个叫做名称空间的单元中,这样就可以用名称空间的名 称来指出使用哪个厂商的产品。
3、c++中定义和声明的区别。定义会导致编译器为变量分配内存空间。而声明则命令计算机使用在其他地方定义的变量。
4、<< 为重新定义操作符
5、 c++程序应当为程序中使用的每个函数提供原型,否则编译器将不知道如何解释这个函数。函数原型对于函数的作用就像变量声明对于变量一样。
6、 不要混淆函数原型和函数定义。函数原型告诉编译器函数名称、返回值类型、参数个数、类型和参数顺序,编译器用函数原型验证函数调用。函数定义中包含了函数 代码。原型结尾的分号表明它是一条语句,这使得它是一个原型而不是函数头。如果省略分号,则编译器将把这行代码解释为函数头,并要求接着提供定义该函数的 函数体。
   注:c++之所以要提供函数原型,是因为c++程序一般将函数的原型与函数的定义(函数体)放在不同的文件中(原型一般放在.h头文件中)以实现函数的复 用;为了使编译器在进行编译使能够更快速的对所遇到的函数进行解析,避免在全部文件中查找该函数的定义(即函数体),所以引入了函数原型,主要用于告诉编 译器函数的参数及返回类型,编译器根据函数原型对函数进行验证,提高编译效率,节省编译时间。
   假设在某个文件中调用了一个函数,C++将根据文件中的函数原型进行查找,如果该函数是静态的(即函数原型前有static关键字)则编译器只在当前文件中查找函数定义(即函数体);否则,编辑器将在所有程序文件中进行查找。
7、C++的字节由至少能够容纳实现的基本字符集的相邻位组成,也就是说,可能取值的数目必须等于或超过字符数目。如Unicode,因此可能使用16位甚至32位的字节。
8、sizeof操作符返回类型或变量的长度,单位为字节。注意,"字节"的含义依赖于实现,因此,在一个系统中两个字节的int可能是16位,而在另一个系统中可能是32位。
9、sizeof动态分配内存时,计算需要分配内存空间的大小。sizeof是个操作符不是个函数,strlen是函数。
10、#define和#include一样是预处理器编译指令。
11、unsigned 是unsigned int的缩写
12、c++整型常量,如果第一位为1-9则是十进制;如果第一位为0,第二位为1-7,则为八进制;如果前两位为0x则为十六进制。例如:42、042、0x42。
13、wchar_t(宽字符类型)可以表示扩展字符集。通过加前缀L来指示宽字符常量和宽字符串。例如:wchar_t bob = L'P',在支持两字节wchar_t系统中,这段代码吧字符p存储在了一个两个字节的内存单元中。
14、C++中bool类型,0是false,1是true。任何数字或指针值都可以被隐式转换为bool值。任何非零值都被转换为true。
15、c++源文件中开头所包含的编译指令总有一种魔咒的力量,新手c++程序员可以通过阅读和体验来了解每个头文件的功能和作用,再一一包含他们,以便程序能够运行。在很多情况下,头文件和源文件都是信息和知识的很好来源。
16、浮点数,默认情况下程序将浮点数值存储为double类型,例如:8.24。如果希望存储为float类型,请使用f或F后缀,例如:8.24F。如果希望存储为long double类型,请使用l或L后缀,例如:8.24L。
17、c++数组的定义。typeName arrayName[arraySize]。其中arraySize必须是常数或常量表达式,即其中所有的值在编译时都是已知的。
18、 如果将sizeof操作符用于数组名,得到的是整个数组中的字节数。但如果将sizeof用于数组元素,则得到的是元素的长度(单位为字节)。这表明数组 元素只是一个变量。例如:int yams[3] 则yams[1]只是一个int变量。sizeof(yams)为数组所占内存的字节长度,而sizeof(yams[1])是一个int变量所占内存的 字节长度。
19、让编译器计算数组的元素个数是一种很糟糕的做法,因为其计数可能与你想象的不一样。
例如:int things[] = {1,3,5}; int num_elements = sizeof(things)/sizeof(int);
20、c语言风格字符串,具有一种特殊的性质:以空字符结尾,空字符被写作\0,其ASCII码为0,用来标记字符串的结尾。例如:char dog[5] = {'f','a','t','s','\0'}
21、另一种将字符数组初始化为字符串的方法:char bird[10] = "Mr.Cheeps";用引号括起来的字符串隐式的包含结尾的空字符。
22、 未初始化的数组,其内容是未定义的,函数strlen()从数组的第一个元素开始计算字节数直到遇到空字符。例如:char ch[20]; cout << strlen(ch); 由于ch数组未进行初始化,所以strlen(ch)输出的是遇到第一个空字符的字节数。可能大于20,也可能小于20。
23、一定要在使用指针之前,将指针初始化为一个确定的、适当的地址。 例如:int* fellow; *fellow = 23;由于fellow未被初始化,它可能是任何值,则23可能被存储在内存中一个不确定的地方,从而导致一些隐匿难以跟踪的bug。
24、 c++中不允许将整形数字作为地址,直接赋值给指针。例如:char* str; str = 0xF8000000;// type mismatch。应通过强制类型转换将数字转换为地址类型。例如:char* str; str = (int*)0xF8000000;
25、在c语言中可以使用malloc()来分配内存;但c++中有更好的方法—new操作符。
26、变量是在编译时分配的、有名称的内存。
27、指针被初始化为变量的地址,只是为可以通过名称直接访问内存提供了一个别名。指针真正的作用在于,在运行阶段存储未命名的内存地址。例如:int* pn = new int;
28、在c++中值为0的指针被称为空值指针。c++确保空值指针不会指向有效的数据,因此它常被用来表示操作符或函数失效,如果成功,则返回一个有用的指针。在内存耗尽的情况下使用new操作,将返回0。
29、 使用delete释放内存,当使用new获取分配的内存,在使用完毕后,需要用delete释放内存。例如:int* ps = new int; *ps =100; delete ps;这将释放ps所指向的内存,单不会删除指针ps本身。对空值指针应用delete是安全的。
30、使用 delete的关键在于,将它用于释放new 分配的内存。这并不等于一定是用new操作符产生的指针,因为其他的指针也可以通过赋值指向相同的内存地址。例如: int* ps = new int; int* p = ps; delete p;同样可以起到释放内存的作用。但是这样写,会增加错误删除同一块内存两次的可能性,应尽量避免这样的使用。
31、指针变量加1后,其增加的值等于指向的类型占用的字节数。
32、 指针与数组名的区别:指针是一个存储内存地址的变量,并且可以进行指针运算。而数组名是一个代表内存地址的常量。int* pi;int a[3] ={1,2,3}; pi=a;cout <<"point address is" << &pi <<"point content is" <33、(.)句点操作符,又叫成员关系操作符,用于访问结构的成员。但是如果是指向结构的指针,则需要通过(->) 箭头成员操作符,访问结构其成员。例如:struct inf{  char* name; int  volume;  };   inf* ps = new inf;   ps->name = "book";   (*ps).volume = 10;
34、c++建立别名的方式有两种,一种是使用预处理#define char_b char;另一种是使用关键字typedef来装创建typedef char char_b;
35、 为什么需要函数原型?函数原型可以让编译器在进行编译时了解函数的信息。否则编译器在进行编译时遇到函数必须停止,并查找相关的函数定义,这将大大降低效 率。另外更重要的是,由于c++允许将程序存放在多个文件中,单独编译这些文件,再组合起来,所以当函数定义不在当前文件中时,编译器可能无法访问到函数 代码。
36、为避免在函数中修改数组的值,可以在声明形参时使用关键字const。例如:void show_array(const double arr[],int n);
37、 指向常量的指针:让指针指向一个常量,这样可以防止使用指针来修改所指向的值。但是指针所指向的地址是可以修改的。例如:int age = 20;int old = 30;const int*  pt = &age;pt=&old; 这样无法通过*pt修改变量age的数据。需要注意的是如果const int age=20; int* pt=&age;这样赋值是错误的,因为age是常量,而通过*pt是不能修改常量的,所以应改为const int age=20;const int* pt=&age;即可以将const数据的地址或非const数据的地址赋值给指向常量的指针,但只能将非const数据的地址赋值给非指向常量 的指针。
38、指针本身声明为常量,这样可以防止改变指针所指向的位置。例如:int age=20;  int* const pt = &age;
39、 int x[2][3],二维数组名x,与x[0]的值虽然相同但是含义不同;数组名x代表二维数组的首地址。而x[0]仅代表二维数组中第一行数据的首地址,只 不过这两个首地址是重合的。C++需要根据我们写法的不同,来区分这两个相同数值的含义。在多维数组中,*x与x[0]代表的是同一事物,即第一行数据的 首地址。
40、函数指针。例如:int sum(int x,int y); /*函数指针的定义*/int (*pt)(int x,int y); pt = sum;int s = sum(5,6);int ss = (*pt)(5,6);其中(*pt)表示的是函数指针类型,pt则表示函数指针所指向的地址;这点和int* x中的x一样,int* x的代表x是指向整型的指针。而(*pt)则代表的是指向函数的指针。
41、内联函数,在编译时编译器将使用函数代码代替函数调用,这点有点像c 语言中#define定义,但是内联函数与宏不同,宏定义仅仅进行文本替换,而内联函数本事是一个函数,具有函数的所有特征。例如:程序中有10个地方使 用了内联函数,编译时将会替换这10处的函数调用,所以会增加代码占用内存的大小,但是可以相应提高运行速度。注意:内联函数不能递归。
42、引 用变量,在C和C++中&符号被用来指示变量的地址。而在C++中&符号还有另外一个含义,在声明变量时,使用&符号来进行变量 的引用声明。引用变量最主要的用途是用作函数的形参。引用和指针并不相同,在声明引用时,必须进行初始化。例如:int x=10; void seq(int& a); seq(x); void seq(int& a){ cout << a+1 << endl;}
43、请不要将函数定义或变量声明放到头文件中,这样虽然有时可行,但是会造成很多麻烦。头文件中常包含的内容: 函数原型、使用#define或const定义的符号常量、结构声明、类声明、模板声明、内联函数。不要在头文件中使用using编译指令。如果非要使用 编译指令using,请将其放在预处理#include指令之后。

44、自动变量(auto),在函数定义中声明变量(包括函数参数)。自动变量被存储在内存的堆栈中,初始化数据不确定。
45、静态变量(static),在函数外定义的变量和使用关键字static定义的变量为静态变量。
46、动态变量(new),使用new操作符分配的内存将一直存在,直到使用delete操作符将其释放。
47、 创建链接性为外部的静态持续变量,必须在代码块的外边定义他,例如:int global =1000; //external linkage。链接性为外部静态持续的变量可以被程序中的其他文件使用。其他文件中要使用该变量,必须在引用声明中使用关键字extern。
48、创建链接性为内部的静态持续变量,必须在代码块的外边定义它,并使用static限定符,例如:static int one_face=50; //internal linkage。链接性为内部的静态持续变量只能被包含上述代码的文件中使用。
49、创建没有链接的内部静态持续变量,必须在代码块内部定义它,并使用static限定符,例如:{static int count=10;} //no linkage。作用域为局部,没有链接性,只能在作用域内部使用。
50、所有静持续变量都具有2个初始化特征:未初始化的静态变量所有位被设置为0;只能使用常量表达式来初始化静态变量。

51、c++中提供了作用域解析操作符,用双冒号表示(::)。例如:在函数中将该操作符放在变量名称前表示,使用该变量的全局版本。例如:{cout << ::global;}

52、类的成员为私有(private),私有成员只能在类的本身的方法内访问,类的对象不能够访问私有成员,私有成员不能被派生类继承。默认情况下,类的成员为私有。
53、保护成员(protected)不能够被对象访问,但能够被派生类继承。
54、公有成员(public),能够被类的所有对象访问,并能够被派生类继承。

55、函数原型 const Stock & topval(const Stock & s) const;该函数隐式地访问一个对象(自身),显示地访问另一对象(形参),并返回一个对象的引用。括号中的const表明,该函数不会修改被显示地访 问的对象;而括号后的const表明,该函数不会修改被隐式地访问的对象。由于该函数返回了两个const对象之一得引用,因此返回类型也应为const 引用。
56、this指针,指向对象本身的地址。(*this)就是对象本身。
57、不能在类的声明中初始化成员变量,这是因为声明描述了如何分配内存,但并不分配内存。只有当类被实例化为具体的对象时,才会分配内存,成员变量的初始化需要在构造函数中进行。(类作用域章节)
58、类的友元函数是非成员函数,其访问权限与成员函数相同。由于友元函数不是成员函数,因此不能使用成员操作符来调用。

59、类的构造函数初始化列表的作用:没有默认构造函数的类的类型成员以及const或引用类型的成员,都必须在构造函数初始化列表中进行初始化。
60、构造函数初始化列表仅指定用于初始化成员的值,并不指定这些初始化成员执行的顺序。初始化成员的顺序就是定义成员的顺序,与构造函数初始化列表中的顺序无关。
61、 使用默认构造函数定义一个对象的正确方式是去掉最后的空括号。例如:Sales_item myobj();使用这种方式调用Sales_item类的默认构造函数,初始化myobj变量时,编译器会将上述语句解释为一个函数的声明(myobj 函数返回Sales_item类型),从而产生二义性造成错误。所以调用默认构造函数进行初始化正确的方式是,去掉最后的括号,例如: Sales_item myobj;或者是Sales_item myobj = Sales_item();
62、单形参构造函数应该设置为 explicit 以避免隐式转换可能产生的错误。explicit 关键字只能用于类内部的构造函数声明上。在类的定义体外部所做的定义上不再重复它。例如:
   class Sales_item {
     public:
 explicit Sales_item(std::istream &is);
   }
63、pair 的数据成员为 public,然而下面这段代码却不能编译,为什么? pair p2 = {0, 42}; // doesn't compile, why?
    答:因为pair类定义了构造函数,所以尽管pair 的数据成员为 public,也不能用显示初始化方式。正确为:pair p2(0,42);

64、非 const 引用只能绑定到与该引用同类型的对象。const 引用则可以绑定到不同但相关的类型的对象或绑定到右值。
65、头文件经常 #include 其他头文件。头文件定义的实体经常使用其他头文件的设施。例如,使用 Sales_item 头文件的程序也可能使用 string 库。该程序不会(也不应该)知道 Sales_item 头文件使用了 string 库。
66、 每一个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区或堆。C 语言程序使用一对标准库函数 malloc 和 free 在自由存储区中分配存储空间,而 C++ 语言则使用 new 和 delete 表达式实现相同的功能。

67、数组长度后面的一对空圆括号,对数组元素做值初始化
 int *pia2 = new int[10] (); // array of 10 uninitialized ints
 圆括号要求编译器对数组做值初始化,在本例中即把数组元素都设置为0。
 C++ 虽然不允许定义长度为 0 的数组变量,但明确指出,调用 new 动态创建长度为 0 的数组是合法的:
   char arr[0];            // error: cannot define zero-length array
   char *cp = new char[0]; // ok: but cp can't be dereferenced
 用 new 动态创建长度为 0 的数组时,new 返回有效的非零指针。该指针与 new 返回的其他指针不同,不能进行解引用操作,因为它毕竟没有指向任何元素。而允许的操作包括:比较运算,因此该指针能在循环中使用;在该指针上加(减)0; 或者减去本身,得 0 值。

 68、strlen 返回的是字符串的长度,并不包括字符串结束符,在获得的字符串长度上必须加 1 以便在动态分配时预留结束符的存储空间。
 69、 可以声明一个类而不定义它,例如:class Screen; // declaration of the Screen class,这个声明,有时称为前向声明。在声明之后、定义之前,类 Screen 是一个不完全类型,即已知 Screen 是一个类型,但不知道包含哪些成员。不完全类型(incomplete type)只能以有限方式使用。不能定义该类型的对象。不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类 型或返回类型的函数。

 70、因为只有当类定义体完成后才能定义类,因此类不能具有自身类型的数据成员。然而,只要类名一出现就可以认为该类已声明。因此,类的数据成员可以是指向自身类型的指针或引用:
     class LinkScreen {
         Screen window;
         LinkScreen *next;
         LinkScreen *prev;
     };

71、基类指针可以在不进行显示类型转换的情况下指向派生类对象。不过基类指针或引用只能用于调用基类方法。不可以将基类对象和地址赋给派生类引用和指针。
72、 在基类和扩展类的声明中,如果调用成员函数方法是通过引用或指针而不是对象调用的,virtual关键字将决定是使用基类中的方法,还是扩展类中的方法。 如果成员函数声明中没有使用virtual关键字,程序将根据引用类型或指针类型选择成员函数。如果使用了virtual,程序将根据引用或指针指向的对 象的类型来选择方法。例如:
   class Brass{
   private:
   enum {MAX = 35};
   char fullName[MAX];
   public:
 virtual void ViewAcct() const;
 virtual ~Brass(){}

   } //基类
   class BrassPlus :public Brass{
   private:
 double maxLoan;
   public:
 virtual void ViewAcct() const;
   } //扩展类
  
   //如果ViewwAcct不是虚拟的(成员函数声明中不带virtual关键字)则
   Brass dom;
   BrassPlus dot;
   Brass & b1_ref = dom;
   Brass & b2_ref = dot;
   b1_ref.ViewAcct();    //掉用的是Brass::ViewAcct();
   b2_ref.viewAcct();  //调用的是Brass::ViewAcct();
  
   //如果ViewwAcct是虚拟的(成员函数声明中带virtual关键字)则
   Brass dom;
   BrassPlus dot;
   Brass & b1_ref = dom;
   Brass & b2_ref = dot;
   b1_ref.ViewAcct();    //掉用的是Brass::ViewAcct();
   b2_ref.viewAcct();  //调用的是BrassPlus::ViewAcct();

记住:如果在派生类中重新定义基类的方法,通常应将基类方法声明为虚拟的,这样程序将根据对象的类型而不是引用或指针的类型来选择方法版本。为基类声明一个虚拟析构函数也是一种惯例。注意,关键字virtual只用于类声明的方法原型中,而没有用于程序的方法定义中。

73、虚函数的实现:编译器给每个对象添加一个隐藏成员,隐藏成员中保持了一个指向

74、在基类对象指针数组中,调用delete删除使用new创建的数组成员,需要使用虚拟的析构函数,以便程序能够正确的调用指针所指向的对象的析构函数。
    //基类指针数组
    Brass* p_clients[4];
    for(int i=0;i<4;i++){
 if(i!=2){
    p_clients[i] = new Brass;  //基类对象指针
 }else{
    p_clients[i] = new BrassPlus; //派生类对象指针
 }
    }
    for(i=0;i<4;i++){
 delete p_clients[i];   //使用虚拟的析构函数,可以使程序正确的调用指针所指向对象的析构函数。
   
    }

75、只要类的成员方法不修改调用对象,就应该将其声明为const.
76、可以通过将构造函数声明为 explicit,来防止在需要隐式转换的上下文中使用构造函数

77、多重继承中派生类的基类构造顺序是按照基类在派生类列表中的出现次序进行的。例如:class Bear : public ZooAnimal {    };class Panda : public Bear, public Endangered {    }; 构造顺序

78、声明常常使用extern关键字,如果我们只声明变量而不是定义它,则要求使用extern.对于函数声明,extern是可选的。不带函数体的函数名连同参数表盒返回类型,自动地作为一个声明。
79、c++允许将任何类型的指针赋给void*(这是void*的最初意图,它要求void*足够大,以存放任何类型的指针),但不允许将void*指针赋值给任何其他类型的指针。

80、不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存。静态数据成员在类声明中声明,在包含类方法的文件中进 行初始化。初始化时使用作用域操作符来指出静态成员所属的类。例如:int StringBad::num_strings = 0;注意,初始化语句指出了类型,并使用了作用域操作符。
81、在构造函数中使用new来分配内存时,必须在相应析构函数中使用delete来释放内存。如果使用new[]来分配内存,则应使用delete[]来释放内存。例如:char* str;str = new char[10];delete [] str;

82、当使用一个对象来初始化另一个对象时,编译器将自动调用复制构造函数。例如:StringBad sports;String sailor = sports;该初始化语句等价于StringBad sailor = StringBad(sports);复制构造语句被执行。
以下4种声明都将调用复制构造函数:
StringBad ditto(motto);
StringBad metoo = motto;
StringBad also = StringBad(motto);
StringBad * pStringBad = new StringBad(motto);
其中中间的2种声明可能会使用复制构造函数直接创建metoo和also,也可能使用复制构造函数生成一个临时对象,然后将临时对象的内容赋值给metoo和also。这取决于编译器的实现。
复制构造函数原型Class_name(const Class_name &),复制构造函数将创建一个形参对象的副本。
83、带参数的构造函数也可以是默认构造函数,只要所有参数都有默认值。例如:klunk(int n=0){cn=n;}
84、如果类中包含了使用new初始化的指针成员,应该显示的定义一个复制构造函数,以复制指向的数据而不是指针,这被称为深度复制。
85、 赋值操作符原型 Class_name & Class_name::operator=(const Class_name &); 注意等号右边括号中的&代表的是形参类对象的引用,而等号左边的&代表的是类对象本身this的引用。将已有对象赋给另一个对象时,将使 用重载的赋值操作符。初始化对象时,并不一定会使用赋值操作符。
86、静态成员函数不能通过对象进行调用,也不能通过this指针调用。如果静态成员函数是在公有部分声明的,则可以使用类名和作用域解析操作符来调用他。

阅读(1020) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏的详细解释

给主人留下些什么吧!~~