您的位置:首页 > 编程语言 > C语言/C++

C++易错知识点总结(一)...

2010-07-11 09:13 381 查看
1. 在类内部定义的函数默认为inline类型的

 

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;
}
 
 
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息