读《高质量C++编程》总结
2014-04-26 17:30
253 查看
今天翻了一遍《高质量C++编程》,为了以后再次回顾,做了如下记录与一些自己的总结。
1.头文件包含问题
为了防止头文件被重复引用,应当用 ifndef/define/endif 结构产生预处理块。
也可以使用另一种方式:#pragma once 相信很多人知道,作用和上面是一样的。
2.循环语句效率
在多重循环中,如果可以,应当将最长的循环放在最内层,最短的循环放在最外层,以减少 CPU 跨切循环层的次数
如:
for(i = 0; i<500; i++)
{
for(j=0; j<10; j++)
{
//xxx
}
}//不良写法
应改为:
for(i = 0; i<10; i++)
{
for(j=0; j<500; j++)
{
//xxx
}
}
另外,如果循环体内存在逻辑判断,并且循环次数很大,可以将逻辑判断移到循环体的外面。
3.switch语句
Java中
1. byte、char、short、int四种基本类型以及它们的包装类(需要Java5.0/1.5以上版本支持)都可以用于switch语句。
2. long、float、double、boolean四种基本类型以及它们的包装类(在Java所有版本中)都不能用于switch语句。
3. enum类型,即枚举类型可以用于switch语句,但是要在Java5.0(1.5)版本以上才支持。
4. 所有类型的对象(包括String类,但在Java5.0/1.5以上版本中,该项要排除byte、char、short、int四种基本类型对应的包装类)都不能用于switch语句。
C++中
1. char、short、int、long、bool四种基本类型都可以用于switch语句。
2. float、double都不能用于switch语句。
3. enum类型,即枚举类型可以用于switch语句。
4. 所有类型的对象都不能用于switch语句。(比如string,可以自己试试)
4.常量
1.不能在类声明中初始化 const 数据成员
class A
{…
const int SIZE = 100; // 错误,企图在类声明中初始化 const 数据成员
int array[SIZE]; // 错误,未知的 SIZE
};
2.const 数据成员的初始化只能在类构造函数的初始化表中进行
class A
{…
A(int size); // 构造函数
const int SIZE ;
};
A::A(int size) : SIZE(size) // 构造函数的初始化表
{
…
}
3.C++中的常量用const声明,C语言中用的是#define。
const最大的用处是用在函数的参数修饰,比如函数的一个参数是指针,如果这个函数在以后的工作中不会改变指针指向的变量的话,要在指针前加const,避免以后意外的改变。
5.static成员变量与函数
static类型的类成员变量必须在类外初始化;
static成员函数不依赖于类,相当于类里的全局函数(可以由该类对象调用,也可以 类名::函数名()的形式调用)
static成员函数相当于把访问范围限制在所在的类中! 注意:不能访问类中非static成员变量以及成员函数。
static成员函数在实际中可以用作线程函数。
6.指针与引用
如果函数的返回值是一个对象,有些场合用“引用传递”替换“值传递”可以提高效率。而有些场合只能用“值传递”而不能用“引用传递” ,否则会出错。
例如:
class String {… // 赋值函数 String & operate=(const String &other); // 相加函数,如果没有 friend 修饰则只许有一个右侧参数 friend String operate+( const String &s1, const String &s2); private: char *m_data; }:
String 的赋值函数 operate = 的实现如下:
String& String::operate=(const String &other) { if (this == &other) return *this; delete m_data; m_data = new char[strlen(other.data)+1]; strcpy(m_data, other.data); return *this; // 返回的是 *this 的引用,无需拷贝过程 }
对于赋值函数,应当用“引用传递”的方式返回 String 对象。如果用“值传递”的
方式,虽然功能仍然正确,但由于 return 语句要把*this 拷贝到保存返回值的外部存
储单元之中,增加了不必要的开销,降低了赋值函数的效率。
String 的相加函数 operate + 的实现如下:
String operate+(const String &s1, const String &s2) { String temp; delete temp.data; // temp.data 是仅含‘\ 0’ 的字符串 temp.data = new char[strlen(s1.data) + strlen(s2.data) +1]; strcpy(temp.data, s1.data); strcat(temp.data, s2.data); return temp; }
对于相加函数,应当用“值传递”的方式返回 String 对象。如果改用“引用传递”,
那么函数返回值是一个指向局部对象 temp 的“引用”。 由于 temp 在函数结束时被自动销毁,将导致返回的“引用”无效
7.extern c的问题
如果 C++ 程序要调用已经被编译后的 C 函数,该怎么办?
假设某个 C 函数的声明如下:
void foo(int x, int y);
该函数被 C 编译器编译后在库中的名字为_foo,而 C++编译器则会产生像_foo_ int_ int之类的名字用来支持函数重载和类型安全连接。由于编译后的名字不同,C++ 程序不能直接调用 C 函数。C++ 提供了一个 C 连接交换指定符号 extern “C”来解决这个问题。
例如:
extern “C”
{
void foo(int x, int y);
… // 其它函数
}
或者写成
extern “C”
{
#include “myheader.h”
… // 其它 C 头文件
}
这就告诉 C++ 编译译器,函数 foo 是个 C 连接,应该到库中找名字_foo 而不是找
_foo_int _ int 。C++ 编译器开发商已经对 C 标准库的头文件作了 extern “C”处理,所以我们可以用#include 直接引用这些头文件。
8.参数缺省值
参数缺省值只能出现在函数的声明中,而不能出现在定义体中。
例如:
void Foo(int x=0, int y=0); // 正确,缺省值出现在函数的声明中
void Foo(int x=0, int y=0) // 错误,缺省值出现在函数的定义体中
{
…
}
9.运算符重载
如果运算符被重载为全局函数,那么只有一个参数的运算符叫做一元运算符,有两个参数的运算符叫做二元运算符。
如果运算符被重载为类的成员函数,那么一元运算符没有参数,二元运算符只有一个右侧参数,因为对象自己成了左侧参数
10.重载、覆盖与隐藏
成员函数被重载的特征:
(1 )相同的范围(在同一个类中);
(2 )函数名字相同;
(3 )参数不同;
(4 )virtual 关键字可有可无。
覆盖是指派生类函数覆盖基类函数,特征是:
(1 )不同的范围(分别位于派生类与基类);
(2 )函数名字相同;
(3 )参数相同;
(4 )基类函数必须有 virtual 关键字。
隐藏:
(1 )如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual
关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2 ) 如果派生类的函数与基类的函数同名, 并且参数也相同, 但是基类函数没有 virtual
关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
(未完待续...)
相关文章推荐
- c++-类的初始化列表
- LeetCode 求和问题总结(2sum,3sum,ksum)
- C++对象内存布局--虚基类表的使用
- C++ Primer笔记(十六)命名空间
- C/C++
- NYOJ-325-zb的生日
- 在const和非const成员函数中避免重复
- C++智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> )
- c语言访问MySQL数据库
- LRU的C++实现
- C++:继承
- C++运算符号重载
- VC++笔记九
- 走进C++世界------临时对象使用
- WINDOWS 32C++多线程举例
- C++获取代码运行时间
- C++嵌套类nested class (内部类)
- C++函数调用机制初级
- 使用C++11继承控制关键词来防止在类层次结构上的不一致
- C++学习笔记(3)