代码改变世界

随笔分类 -  C++

Effective C++ 学习笔记(14)

2011-08-03 23:59 by Daniel Zheng, 286 阅读, 收藏, 编辑
摘要: 在operator=中检查给自己赋值的情况做类似下面的事时,就会发生自己给自己赋值的情况:class X { ...};X a;a = a; 这种事做起来好象很无聊,但它完全是合法的,所以看到程序员这样做不要感到丝毫的怀疑。更重要的是,给自己赋值的情况还可以以下面这种看起来更隐蔽的形式出现:a = b; 如果 b 是a 的另一个名字(例如,已被初始化为a 的引用),那这也是对自己赋值,虽然表面上看起来不象。这是别名的一个例子:同一个对象有两个以上的名字。在本条款的最后将会看到,别名可以以大量任意形式的伪装出现,所以在写函数时一定要时时考虑到它。 在赋值运算符中要特别注意可能出现别名的情况,其理 阅读全文

Effective C++ 学习笔记(13)

2011-08-03 22:57 by Daniel Zheng, 197 阅读, 收藏, 编辑
摘要: 在operator=中对所有数据成员赋值template<class T>class NamedPtr{public: NamedPtr(const string & initName, T * initPtr); NamedPtr & operator= (const NamedPtr & rhs);private: string name; T * ptr;};template<class T>NamedPtr<T> & NamedPtr<T>::operator=(const NamedPtr<T> 阅读全文

Effective C++ 学习笔记(12)

2011-08-03 16:03 by Daniel Zheng, 191 阅读, 收藏, 编辑
摘要: 让operator=返回*this的引用要完成如 a = b =c 这样的操作所以返回值不能为void,对这个表达式,编译器的理解为 a = (b = c),所以operator=可以返回左值或者右值,但有时候我们也需要这样的操作 (a = b) = c ,b赋值给a,然后c赋值给a。所以operator=应该返回右值。、由此分析,我们得到operator=的函数声明为 T & T::operator=(const T &)。假设我们传入的参数为a,则a为const T & 类型,与返回类型不符,所以不能作为返回值。如果我们去掉参数的const,首先,这样不安全,函数内 阅读全文

Effective C++ 学习笔记(11)

2011-08-03 15:01 by Daniel Zheng, 239 阅读, 收藏, 编辑
摘要: 确定基类有虚析构函数class A{public: A() { cout<<"A constructor"<<endl; } ~A() { cout<<"A destructor"<<endl; }};class B: public A{public: B() { cout<<"B constructor"<<endl; } ~B() { cout<<"B destructor"<<endl; }};int main() 阅读全文

Effective C++ 学习笔记(10)

2011-08-03 14:28 by Daniel Zheng, 210 阅读, 收藏, 编辑
摘要: 初始化列表中的成员列出的顺序和它们在类中声明的顺序相同class A{public: A(int a):j(a),i(j*2) { cout<<"A constructor"<<endl; } void Get() const { cout<<"i="<<i<<endl<<"j="<<j<<endl; }private: int i; int j;};int main(){ A a(10); a.Get(); return 0;} 执行结果 阅读全文

Effective C++ 学习笔记(9)

2011-08-03 14:12 by Daniel Zheng, 230 阅读, 收藏, 编辑
摘要: 尽量使用初始化而不是在构造函数里赋值class Test{ public: int a; float b; Test():a(0),b(0.0) { } Test() { a=0; b=0.0; }}; 初始化与赋值构造函数对内置类型区别不大,而对于非内置类型,如string,为了避免两次构造函数的调用,推荐使用初始化。以下是必须使用初始化的情况:对于const和引用类型,只能初始化,不能赋值。如果我们的类A有一个类B的成员,而类B没有默认构造函数,而只有带参数的构造函数,这个时候要对类B进行初始化,只能调用初始化表。class A{public: A(int a) { cout<< 阅读全文

(转)C++函数后加const的意义

2011-05-11 10:51 by Daniel Zheng, 2249 阅读, 收藏, 编辑
摘要: C++函数后加const的意义一些成员函数改变对象,一些成员函数不改变对象。 例如: int Point::GetY() { return yVal; } 这个函数被调用时,不改变Point对象,而下面的函数改变Point对象: void Point:: SetPt (int x, int y) { xVal=x; yVal=y; } 为了使成员函数的意义更加清楚,我们可在不改变对象的成员函数的函数原型中加上const说明:class Point { public: int GetX() const; int GetY() const; void SetPt (int, int); void 阅读全文

Effective C++ 学习笔记(8)

2011-04-14 10:49 by Daniel Zheng, 232 阅读, 收藏, 编辑
摘要: 为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符 下面是一个表示String对象的类: class String { public: String(const char *value); ~String(); ... private: char *data; }; String::String(const char *value) { if(value) { data=new char[strlen(value)+1]; strcpy(data,value); } else { data=new char[1]; *data='\0'; } } inline Stri 阅读全文

Effective C++ 学习笔记(7)

2011-04-13 11:05 by Daniel Zheng, 223 阅读, 收藏, 编辑
摘要: 析构函数里对指针成员调用delete 大多数情况下,执行动态内存分配的类都在构造函数中使用new分配内存,然后在析构函数中使用delete释放内存。当这个类经过维护,升级后,情况将变得复杂。每增加一个指针成员都有进行如下的操作: 在每个构造函数中对指针初始化。指向相应的内存地址或者初始化为0,即空指针。 删除现有内存,通过赋值操作符分配给指针新的内存。 在析构函数里删除指针。 对于一个没有用到new去初始化的指针,不用delete去删除。 阅读全文

Effective C++ 学习笔记(6)

2011-04-13 10:17 by Daniel Zheng, 267 阅读, 收藏, 编辑
摘要: 对应的new和delete要采用相同的形式 我们看下面的代码: string *stringArray=new string[100]; ... delete stringArray; 上述代码看上去没错,实际上程序的运行情况将是不可预测的。stringArray指向的100个string对象中的99个不会被正确的摧毁,因为他们的析构函数永远不会被调用。 使用new的会触发两件事情。首先内存被分配,然后为被分配的内存调用一个或多个构造函数。同样,调用delete时也会触发两件事情。首先是为将被释放的内存调用一个或多个析构函数,然后是释放内存。这里,对于一个delete操作而言会有这么一个问题: 阅读全文

Effective C++ 学习笔记(5)

2011-04-13 09:53 by Daniel Zheng, 257 阅读, 收藏, 编辑
摘要: 尽量使用C++风格的注释 C风格的注释/* */在C++中仍然可以使用,但是推荐使用C++中的尾行注释。 很多时候,你需要去注释掉一些代码,使用C++风格的尾行注释如下: if(a>b) { //a=a^b; //swap a and b //b=a^b; //a=a^b; } 如果使用C风格的注释: if(a>b) { /*a=a^b; /*swap a and b*/ a=a^b; a=a^b; */ } 上述代码实际上注释的只是一行而已。 阅读全文

Effective C++ 学习笔记(4)

2011-04-12 21:47 by Daniel Zheng, 245 阅读, 收藏, 编辑
摘要: 尽量使用new和delete而不是malloc和free malloc和free是C语言对应的内存操作函数,在C++中无法在分配与释放内存是自动调用构造函数与析够函数。 使用malloc给10个string对象的数组分配内存: string *stringArray1=static_cast<string*>(malloc(10*sizeof(string))); stringArray1指向的内存空间的确可以容纳10个string对象,但没有创建这些对象,仅仅只是分配了这么大的内存空间而已。实际使用这些内存初始化数组里的对象将很困难。 使用new进行同样的操作: string * 阅读全文

Effective C++ 学习笔记(3)

2011-04-10 14:42 by Daniel Zheng, 284 阅读, 收藏, 编辑
摘要: 尽量使用<iostream>而不是<stdio.h> scanf与printf不是类型安全的,而且不具有扩展性。 <iostream.h>不是标准C++头文件,命名空间是全局。<iostream>命名空间是str::。 阅读全文

Effective C++ 学习笔记(2)

2011-04-10 13:31 by Daniel Zheng, 340 阅读, 收藏, 编辑
摘要: 尽量使用const和inline而不是#define 尽量使用编译器而不是预处理。 #define定义的宏不会加入符号表,不利于调试。 当使用#define定义常量时,使用const替代:#define ABC 123 => const int ABC=123;定义某个class常量时要同时用static与const修饰,以确保只存在一份拷贝。 当使用#define定义类似函数的宏时,用inline函数替代: 举例: 计算两个对象大小:#define max(a,b) ((a)>(b)?(a):(b)),对于这样的宏一定要加括号,因为预处理器只是完成简单的字符串替代,可能引起意想不 阅读全文

Effective C++ 学习笔记(1)

2011-04-09 19:49 by Daniel Zheng, 282 阅读, 收藏, 编辑
摘要: 视C++为一个语言联邦C。C++以C语言为基础。Object-Oriented C++。C with C++ 的特性:class,encapsulation,inheritance,polymorphism,virtual function等等。Template C++。Generic programming with C++。STL。A template library。 阅读全文