构造/析构/复制运算
来源:互联网 发布:网络主播经常唱的歌曲 编辑:程序博客网 时间:2024/05/18 00:34
Item5 Know what functions C++ silently writes and calls.
编译器可为一个类默认生成默认构造函数、拷贝构造函数和赋值运算符以及析构函数。注意有指针成员的情况下,默认生成的拷贝构造函数和赋值运算符只是简单的拷贝指针的值,指针指向的数据并不拷贝,即执行的为“浅拷贝”。有可能造成指针指向一个已经释放的内存位置。顾在这样的情况下最好自己实现拷贝构造函数、赋值运算符和析构函数。
Item6 Explicitly disallow the use of compiler-generated functions you do not want.
只要自己定义了Item5照哦给你提到的几个函数,编译器便不再默认生成。如果想阻止对象的拷贝和赋值,可将相应的成员函数声明为private并且不予实现。
如下:
class HomeForSale{public:HomeForSale(){}private:HomeForSale(const HomeForSale&);HomeForSale& operator=(const HomeForSale&);};
或者写一个基类,专门组织拷贝动作
如下:
class Uncopyable{protected:Uncopyable() {}~Uncopyable() {}private:Uncopyable(const Uncopyable&);Uncopyable& operator=(const Uncopyable&);};class HomeForSale : private Uncopyable{};
这样将连接期间的错误转到了编译期间。
Item7 Declare destructors virtual in polumorphic base classes.
如果一个基类为实现多态而设计,则应该为其声明一个virtual析构函数。如果class带有任何virtual函数,也应该拥有一个virtual析构函数。
否则出现的问题如下:如果用一个基类指针指向派生类的对象,则在delete基类指针的时候,会出现派生类成分没有被销毁的后果。
如果一个类的设计不是作为基类使用,不是为了多态性,不应该声明virtual析构函数。
Item8 Prevent exceptions from leaving destructors.
析构函数不要抛出异常。如果被析构函数调用的函数可能抛出异常,则析构函数应该捕捉异常,然后吞下他们。
以下为close抛出异常后,程序异常终止。或者去掉std::abort的调用,析构函数将异常吞下。
class DBConnection{public:static DBConnection create();void close(); //失败则抛出异常};class DBConn{public:~DBConn(){try{db.close();}catch(...){
制作运转记录,记下对close的调用失败;
std::abort();}}private:DBConnection db;};
如果客户需要对某个操作函数运行期间抛出的异常做出反应,则类应该提供一个普通的函数执行该该做,而非析构函数。
class DBConn{public:void close(){db.close();closed=true;}~DBConn(){try{if(!closed){db.close();}}catch(...){std::abort();}}private:DBConnection db;bool closed;};
由客户在调用DBConn的close的过程中,去捕捉异常并进行一场处理。
Item9 Never class virtual functions during constructions or destructions.
在构造函数和析构函数中,调用virtual函数,类调用从不下降至派生类。因为在构造的过程中,先构造基类的成员,此时基类还未构造,顾不可能调用一个未构造的对象的成员。“早基类构造期间,virtual函数不是virtual函数”。析构也是同样的道理,析构的过程与构造的过程相反,等到调用基类的析构函数的时候,派生类的析构函数已经调用过。
Item10 Have assignment operators return a reference to *this.
class Widget{public:Widget& operator=(const Widget& rhs){....return *this;}};
对于+=、-=、*=等也成立。
Item11 Handle assignment to self in operator=.
处理方式有如下几种:(1)进行“自我赋值”的检查:
class Widget{public:Widget& operator=(const Widget& rhs){if(this==&rhs)return *this;...}};
(2)复制原有对象的内容
class Bitmap{};class Widget{public:Widget& operator=(const Widget& rhs){Bitmap* pOrig=pb;pb=new Bitmap(*rhs.pb);delete pOrig;return *this;}private:Bitmap *pb;};
(3)copy and swap技术
class Widget{public:void swap(Widget& rhs);Widget& operator=(const Widget& rhs);};Widget& Widget::operator=(const Widget& rhs){Widget temp(rhs);swap(temp);return *this;}
Item 12 Copy all parts of an object.
如果要自定义拷贝构造函数和赋值运算符,则要注意拷贝对象内的所有成员变量及基类的成份。
例如:
class Customer{public:Customer(const Customer& rhs){this->name=rhs.name;}Customer& operator=(const Customer& rhs){if(this==&rhs) return *this;this->name=rhs.name;return *this;}private:std::string name;};class PriorityCustomer:public Customer{public:PriorityCustomer(const PriorityCustomer& rhs):Customer(rhs),priority(rhs.priority){}PriorityCustomer& operator=(const PriorityCustomer& rhs){Customer::operator=(rhs);priority=rhs.priority;return *this;}private:int priority;};
另外,不要尝试在某个拷贝函数实现另一个拷贝函数。应该将重复代码部分放进第三个函数,供拷贝构造函数和赋值运算符调用。
- 构造/析构/复制运算
- C++构造,析构,友元类,对象,static成员,复制构造函数,运算符重载杂谈
- 复制构造函数与赋值运算符
- 运算符重载与复制构造函数
- 复制构造函数和赋值运算符
- Vector::构造,复制构造,析构
- List::构造、复制构造、析构
- 构造,复制,赋值,析构
- 构造/析构/ 赋值运算
- 构造,析构,赋值运算
- String 构造,析构,复制,拷贝构造函数
- 复制构造函数和重载赋值运算符
- string赋值运算符、复制构造函数等实现
- C++:类的复制构造函数、赋值运算符
- C++ 中的赋值运算符重载和复制构造函数
- 带复制构造函数、赋值运算符的模板队列
- 赋值运算符和复制构造函数的区别
- 复制构造函数和=运算符重载的区别
- 6个强大的JavaScript日期操作插件
- 图像数据压缩原理
- sql server字符串非空判断实现方法
- 视频基础知识普及
- 使用 Collections.frequency 找出重复的单词
- 构造/析构/复制运算
- Sql Server触发器的使用
- 李刚java疯狂讲义(笔记)
- C#MD5加密
- 指针函数作为参数
- 数据库建表赋予权限语句
- spring3.1+struts2+hibernate4整合
- 单页Web应用或引领下一代Web新趋势?
- tomcat 运行时出现Cannot create PoolableConnectionFactory (