C++易错知识点总结(一)...
2010-07-11 09:13
381 查看
1. 在类内部定义的函数默认为inline类型的
2. 类的有些成员必须在构造函数初始化列表中进行初始化。对于这样的成员,
在构造函数函数体中对他们赋值不起作用。这样类型的成员有:没有默认构造函数的类类型的成员,
const或引用类型的成员(不管他们本身是什么类型的,如int &a或是string &a),
都必须在构造函数初始化列表中进行初始化。如下例:
3. 关于类成员被初始化的次序:
构造函数初始化列表仅用于初始化成员的值,
并不指定这些初始化执行的次序。成员被初始化的次序就是定义成员的次序。如下例:
以上程序在初始化成员时,
并不是按照初始化列表的次序先初始化m_i, 然后m_j, 而是按照这两个成员定义时的次序, 先初始化m_j, 在m_i, 于是出现了问题,
在初始化列表中m_j(m_i), 也就是想用m_i去初始化m_j ,但这是m_i还没有被初始化, 所以会出现编译错误…
C++ primer中推荐:最好按照与成员声明一致的次序编写初始化列表。而且,
尽可能的避免使用类成员去初始化其他类成员。
4. 如果为类定义了其他的构造函数,
则提供一个默认的构造函数( 无参)几乎总是对的。通常, 在默认构造函数中给成员提供的初始值应该指出该对象是”空”的。
关于编译器提供的默认的构造函数对类成员初始化遵循以下规则,
具有类类型的成员通过运行各自的默认构造函数进行初始化, 内置和复合类型的成员,
如指针和数组, 只对定义在全局作用域中的对象才初始化, 当对象定义在局部作用域时,
内置的或复合类型的成员不进行初始化。所以当类具有内置的或符合类型的成员是, 应该提供自定义的构造函数来初始化这些成员。
当一个类没有提供默认的构造函数时,它将失去以下功能:
(1)
不能用作动态分配数组的元素类型
(2)
静态定义的数组必须为每个元素提供一个显示的初始化式。
(3)
当将这个类型的对象放到诸如vector等的容器中时,
不能只定义容器的大小而不提供元素的初始化式的构造函数。
5.关于构造函数定义的隐式转换
如:
类Test的display()函数需要一个Try类的对象,
单是当我们传给他一个cin时, 编译也能够通过,
这中间编译器给我们做了隐式的转换, 通过Try的构造函数Try(istream &is)进行了转换, 有时这种转换不是必须的,
我们可以在声明构造函数时前面加上关键字explicit来切断这种隐式转换。
如:
这时在调用test.display()时必须显示的构造Try的对象了,
test.display(Try(cin));
推荐:通常情况下, 要将单个形参的构造函数设置为explicit, 防止发生隐式的转换, 造成不必要的错误. Explicit关键字只能用于类内部定义的构造函数声明上,
在类外部定义上不用。
6. 当我们将其他类的成员函数声明为友元函数时,
必须使用该函数所属的类名字加以限定, 如:
7. 一些标记成员函数特殊类型的关键字:
Inline:可以放在声明处, 也可以放在定义处
Static:放在声明处, 无需放在定义处(在类内部定义除外,
数据成员也是如此, 只需在声明处使用static,
定义处不能使用)
Explicit:放在声明处,不能放在定义处(在类内部定义的除外)
Const:声明处, 定义处都要有。
Friend: 放在声明处, 无需放在定义处(在类内部定义除外)
如:
8. const static数据成员在类的定义体中初始化时, 该数据成员仍需要在类的定义体外进行定义,
如:
C++ primer上说const static类型的数据成员即使在类定义内部进行了初始化, 还是需要在类定义外部定义这个数据成员也就是上面的const int Try::MAX;句, 但是好像把这句去了编译也没问题…
9.static类型成员不是类对象的组成部分, 所以static数据成员的类型可以是该成员所属的类类型, 而非static成员只能是改成员所属类类型的指针或引用. 如:
2. 类的有些成员必须在构造函数初始化列表中进行初始化。对于这样的成员,
在构造函数函数体中对他们赋值不起作用。这样类型的成员有:没有默认构造函数的类类型的成员,
const或引用类型的成员(不管他们本身是什么类型的,如int &a或是string &a),
都必须在构造函数初始化列表中进行初始化。如下例:
#include <cstdlib> #include <iostream> #include <string> using namespace std; class Name { public: Name(string str) : m_first(str), m_last(str){}; private: string m_first; string m_last; }; class Person { public: /*Person(string str, int id, int gend) { m_id = id; //main.cpp uninitialized reference member `Person::m_id' m_gend = gend; //main.cpp no matching function for call to `Name::Name()' m_name = str;//main.cpp uninitialized member `Person::m_gend' with `const' type `const int' }*/ //right Person(string str, int id, int gend) : m_name(str), m_id(id), m_gend(gend){}; private: int &m_id; Name m_name; const int m_gend; }; int main(int argc, char *argv[]) { Person per("tom", 1, 2); system("PAUSE"); return EXIT_SUCCESS; }
3. 关于类成员被初始化的次序:
构造函数初始化列表仅用于初始化成员的值,
并不指定这些初始化执行的次序。成员被初始化的次序就是定义成员的次序。如下例:
#include <cstdlib> #include <iostream> using namespace std; class Try { public: Try(int val) : m_i(val), m_j(m_i){}; private: int m_j; int m_i; }; int main(int argc, char *argv[]) { Try try(8); system("PAUSE"); return EXIT_SUCCESS; }
以上程序在初始化成员时,
并不是按照初始化列表的次序先初始化m_i, 然后m_j, 而是按照这两个成员定义时的次序, 先初始化m_j, 在m_i, 于是出现了问题,
在初始化列表中m_j(m_i), 也就是想用m_i去初始化m_j ,但这是m_i还没有被初始化, 所以会出现编译错误…
C++ primer中推荐:最好按照与成员声明一致的次序编写初始化列表。而且,
尽可能的避免使用类成员去初始化其他类成员。
4. 如果为类定义了其他的构造函数,
则提供一个默认的构造函数( 无参)几乎总是对的。通常, 在默认构造函数中给成员提供的初始值应该指出该对象是”空”的。
关于编译器提供的默认的构造函数对类成员初始化遵循以下规则,
具有类类型的成员通过运行各自的默认构造函数进行初始化, 内置和复合类型的成员,
如指针和数组, 只对定义在全局作用域中的对象才初始化, 当对象定义在局部作用域时,
内置的或复合类型的成员不进行初始化。所以当类具有内置的或符合类型的成员是, 应该提供自定义的构造函数来初始化这些成员。
当一个类没有提供默认的构造函数时,它将失去以下功能:
(1)
不能用作动态分配数组的元素类型
(2)
静态定义的数组必须为每个元素提供一个显示的初始化式。
(3)
当将这个类型的对象放到诸如vector等的容器中时,
不能只定义容器的大小而不提供元素的初始化式的构造函数。
5.关于构造函数定义的隐式转换
如:
#include <cstdlib> #include <iostream> using namespace std; class Try { public: Try(istream &is){}; }; class Test { public: void display(Try tr){}; }; int main(int argc, char *argv[]) { Test test; test.display(cin); system("PAUSE"); return EXIT_SUCCESS; }
类Test的display()函数需要一个Try类的对象,
单是当我们传给他一个cin时, 编译也能够通过,
这中间编译器给我们做了隐式的转换, 通过Try的构造函数Try(istream &is)进行了转换, 有时这种转换不是必须的,
我们可以在声明构造函数时前面加上关键字explicit来切断这种隐式转换。
如:
class Try { public: explicit Try(istream &is){}; };
这时在调用test.display()时必须显示的构造Try的对象了,
test.display(Try(cin));
推荐:通常情况下, 要将单个形参的构造函数设置为explicit, 防止发生隐式的转换, 造成不必要的错误. Explicit关键字只能用于类内部定义的构造函数声明上,
在类外部定义上不用。
6. 当我们将其他类的成员函数声明为友元函数时,
必须使用该函数所属的类名字加以限定, 如:
#include <cstdlib> #include <iostream> using namespace std; class Test; class Try { public: void display(Test &test); }; class Test { public: Test() : m_val(10){}; friend void Try::display(Test &test); private: int m_val; }; void Try::display(Test &test) { cout << test.m_val << endl; } int main(int argc, char *argv[]) { Test te; Try tr; tr.display(te); system("PAUSE"); return EXIT_SUCCESS; }
7. 一些标记成员函数特殊类型的关键字:
Inline:可以放在声明处, 也可以放在定义处
Static:放在声明处, 无需放在定义处(在类内部定义除外,
数据成员也是如此, 只需在声明处使用static,
定义处不能使用)
Explicit:放在声明处,不能放在定义处(在类内部定义的除外)
Const:声明处, 定义处都要有。
Friend: 放在声明处, 无需放在定义处(在类内部定义除外)
如:
#include <cstdlib> #include <iostream> using namespace std; void display(); class Try { public: explicit Try(int i); void show() const; static void count(); friend void display(); inline void cal(); private: int m_val; static int m_sta; }; int Try::m_sta = 100; Try::Try(int i) : m_val(i){} void Try::show() const {} void Try::count(){} void display() { cout << "Try::m_sta is: " << Try::m_sta << endl; } inline void Try::cal(){} int main(int argc, char *argv[]) { display(); system("PAUSE"); return EXIT_SUCCESS; }
8. const static数据成员在类的定义体中初始化时, 该数据成员仍需要在类的定义体外进行定义,
如:
#include <cstdlib> #include <iostream> using namespace std; class Try { private: const static int MAX = 100; int array[MAX]; }; const int Try::MAX; int main(int argc, char *argv[]) { system("PAUSE"); return EXIT_SUCCESS; }
C++ primer上说const static类型的数据成员即使在类定义内部进行了初始化, 还是需要在类定义外部定义这个数据成员也就是上面的const int Try::MAX;句, 但是好像把这句去了编译也没问题…
9.static类型成员不是类对象的组成部分, 所以static数据成员的类型可以是该成员所属的类类型, 而非static成员只能是改成员所属类类型的指针或引用. 如:
#include <cstdlib> #include <iostream> using namespace std; class Try { public: Try(const Try &obj = m_obj) : m_mem1(m_obj), m_val(m_obj.m_val){}; private: static Try m_obj; Try *m_mem; Try &m_mem1; const int m_val; //Try m_mem2; //error }; int main(int argc, char *argv[]) { system("PAUSE"); return EXIT_SUCCESS; }
相关文章推荐
- 常见C++面试题及基本知识点总结
- c++知识点总结--new的一些用法
- C++的一些知识点总结
- C++知识点部分总结
- 网络程序设计(C++版) 知识点总结
- C/C++小知识点总结
- C++ 易错知识总结
- C++基础知识总结----类的进阶知识点
- C/C++知识点总结(二)
- C++ 虚函数、纯虚函数、继承、虚表、多态原理相关知识点总结
- 数据结构(c++版)(第2版)第一章:绪论的知识点总结图,制作者:物联1131-22
- C/C++知识点总结(1)
- C/C++知识点总结(2)
- C++中标准库类型vector易忘知识点总结
- C++ 知识点总结复习
- python学习日记,易错知识点总结(1)
- 总结一些笔记上的C和C++知识点
- C++进阶—>易错知识点随笔
- c/c++知识点总结
- 常见的C++面试题与知识点总结(一)