<<effective c++>>笔记
来源:互联网 发布:java社区 编辑:程序博客网 时间:2024/05/19 03:18
0 术语:
0.1 声明
0.1.1 变量: 非class中extern int x; 在类中int x
0.1.2 函数: class GraphNode;
int numDigits(int number);
0.2 定义:提供代码本体
int x; 在类外
int numDigits(int number)
{
......
}
class Widget {
......
};
0.3 初始化
构造函数
class B{
public:
B(int x=0,bool b= true);
}
0.4 调用
bool hasAcceptableQuality(Widget w); 声明
Widget aWidget; 定义
if (hasAcceptableQuality(aWidget)) 调用
Widget w1;
Widget w2(w1) 定义=copy构造函数=编译
w1=w2; 赋值构造=执行
Widget w3=w2; 定义非赋值
item1 :
c++ 由4部分组成。c,object-oriented c++ ; template c++; stl
item2 :
2.1 const 和#define 区别
因为define在预处理器处理宏,所以不在编译的.o中的符号表中
前提补充,预编译如何处理#define,将宏展开,将符号替换,以致符号表中没有宏
const不在预处理中处理,const在编译中处理。
const double AspectRatio=1.653 这是变量定义。
访问权限:指类or对象与main无关。
2.2 inline 函数代替define 宏
#define 定义的类似函数,如#define CALL_WITH_MAX(a,b) f((a) >(b) ?(a):(b))
则会出错
用inline实现,会做参数检查等。不会出错。
item3:
前后限制,整体意义法则
const char *p 值是固定的
char *const p 指针固定
c++以by value返回对象这一事实,子函数内实际改动的是入参的副本。在子函数外,入参值不变。
使用const则在子函数内不会被改动。
传值是主函数 a=10 ; 子函数set (int a ){a=0};主不变;
传引用问题可以参见:polycomm; 主函数str=NULL; 子函数 s(str) {str=malloc(...)} 中分配内存的错误。
const_cast:将常量转成非常量.
const char * c = "sample text";
char *cc = const_cast<char *> (c) ;
static_cast:静态转换,类c转换。
double d=3.14159265;
int i = static_cast<int>(d);
dymatic_cast: 向上转换
CBase* pb;
CDerived d;
pb = dynamic_cast<CBase*>(&d);
reinterpret_cast: 任意转换
item4:
1 构造函数初始化列表叫初始化。
构造函数内叫赋值.初始化列表不在函数内.
初始化列表和赋值相比,赋值需要在创建的时候,先调用default构造函数,在赋值的时候再调用赋值构造函数。
初始化列表只调用一次copy构造函数。
2 规定:总是在初始化列表中列出所有成员变量。
3 成员初始化次序:
3.1 构造函数base class 早于 derived class 被初始化
3.2 class的成员变量总是以其声明次序被初始化
顺序是: 声明早于初始化列表,初始化列表早于构造函数,函数体内赋值。
wfa中新添加的成员变量,不应该在类中,初始化,应该在类的构造函数的初始化列表,初始化。
igt 例题2
4 两种单例模式
4.1 饿汉模式(java叫法)
CarrierManager* CarrierManager::getInstance(void)
{
static CarrierManager obj;
return (CarrierManager*) &obj;
}
这是个对象定义就调用default构造函数,即init了。static保证如果无创建,有则不创建。走下一步,reutrn obj,即return 已有的。
注意obj是对象,直接生成空间。所以不用向指针一样,obj=new CarrierManager();
4.2 懒汉模式(java叫法)
CscdResourceMgr* CscdResourceMgr::sInstance = NULL;
CscdResourceMgr* CscdResourceMgr::getInstance(void)
{
if (sInstance == NULL)
{
sInstance = new CscdResourceMgr();
}
return sInstance;
}
注意先判断。
关键点:
1)私有构造函数
2)静态私有成员
3)公开访问点getInstance
http://www.cnblogs.com/kkgreen/archive/2011/09/05/2166868.html
三:
item5:
1 编译器可以暗自为class 创建default 构造函数(无参数),copy构造函数,赋值构造函数,以及析够函数。(共4个函数)
2 自定义对象的相应构造函数,则default不会产生
item6:
为驳回编译器自动(暗自)提供的机能,可将相应的成员函数声明为private并且不予实现。
item 7
因为c++明白支出,当derived class对象经由一个base class指针删除,而该base class带着一个non-virtual析构函数,
其结果未有定义--实际执行时通常发生的是对象的derived成分没有被销毁。
而子类的析构函数也没被调用。
1 给base class 一个virtual 析构函数。此后删除derived class和基类部分
(虚函数表上的所有的函数,这上面有子有基)
vptr----子实现1----子实现2---基1---基2
2 抽象类不能实例化
3 最深层派生的那个class其析构函数最先被调用,然后是其每一个base class的析构函数被调用。
(和子类调用积累的构造函数,正好相反,是先执行基类的构造函数)
base class 应该声明一个virtual析构函数。如果class 带有任何virtual函数,它就应该拥有一个virtual析构函数。
(有virtual就会基指针指向子类)
classes 的设计目如果不是作为base classes使用,或不是为了具备多态性,就不该声明virtual析构函数。
item8:
析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序
如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class 应该提供一个普通(而非在析构函数中)执行操作
(try--catch)
item9
在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层)
P49 eg1。 本来基类是接口,希望调用子类的实现函数。但是在构造函数期间,先执行基类的,子类还没有创建。这样会出现下面两种情况。
1 由于 logTransaction 是transaction内的一个pure virtual函数,当pure virtual函数被调用,大多执行系统会中止程序
2 如果logTransaction 是个正常的virtual函数并在Transaction内带有一份实现代码。则发现子类本意使用自己的logTraction,结果却是积累的。
会出现指向子类的指针,本意call子类重载的函数,实际调用的是基类的函数.
solution:
无法使用virtual函数从base classes向下调用,在构造期间,你可以籍由“令derived classes将必要的构造信息向上传递至base class构造函数”
item10
令赋值操作符返回一个reference to *this
item11
同《高质量c++》 9.4和9.6的例子
item12 (没看例子)
copying 函数应该确保复制“对象内的所有成员变量”及“所有base class成分”
不要尝试以某个copying函数实现另一个copying函数。应该将共同机能放进第三个函数中,并由两个copying函数共同调用.
item13
智能指针防止分配后,没执行到free,退出造成泄露。
share_ptr有引用计数。
item16
如果你在new表达式中使用[],必须在相应的delete表达式中也使用[].如果你在new表达式中不使用[],一定不要在相应的delete表达式中使用[]
item20
1 子函数传参,内置+stl用传值
2 除了1,其他全用传引用
item22
1 封装(set,get)
2 访问权限限制,有的需要private
item25
vector<int>类型变量vi, 则vector<int>(vi).swap(vi)是什么意思;
vector 内存空间只会增长,不会减少.
比如vi有10000 item。其中9999个erase。仅仅一个有效。但是空间仍然是10000.
{
std::vector<int> tmp;
ivec.swap(tmp);
}
加一对大括号是可以让tmp退出{}的时候自动析构
vi将一个有效的元素,存入tmp中。这样tmp仅仅有一个空间(无效部分不会copy)。然后i和tmp交互。则i只有一个空间。tmp有10000.然后tmp在出大括号后析构.
(一句话,实际是3,4句话含义)
- 《Effective C++》 笔记
- 《Effective C++》阅读笔记
- Effective C++--笔记
- <Effective C++: 资源管理> 笔记
- <<Effective C++>>笔记1
- <<Effective C++>>笔记3
- <<Effective C++>>笔记4
- <<Effective C++>>笔记5
- 《Effective C++》学习笔记
- 《Effective C++》阅读笔记
- 《Effective C++》学习笔记
- 《Effective C++》 笔记
- 《Effective C++》笔记
- Effective C++_Item3笔记
- Effective C++_Item4笔记
- Effective C++_Item5笔记
- Effective C++_Item6笔记
- Effective C++_Item7笔记
- 树和森林
- 在Linux环境下打开来自Windows的文本文件出现乱码
- Random类
- HTTP汇总
- Zurmo(十)之zurmoc所有命令详解(三)
- <<effective c++>>笔记
- c/c++ 头文件梳理
- Python函数式编程
- 回顾2016,畅想2017(20170107)
- 144. Binary Tree Preorder Traversal
- 云计算与分布式的一些关键词
- ViewPager踩坑记
- Tkinter-ListBox基本使用
- PHP中MongoDB数据库的连接、添加、修改、查询、删除等操作实例