* 本工程名CDAProjct表示 C++中的构造/析构和赋值 */
#include <iostream>
#include <stdexcept>
#include <vector>
#include <cstdlib>
using namespace std;
/**************************************/
/* 条款1:c++默默编写并调用的函数 */
/**************************************/
/* default构造函数和析构和析构函数 */
class Another
{
public:
Another() { cout<<"This is Another's constrctor!"<<endl; }
~Another() { cout<<"This is Another's desconstructor!"<<endl; }
};
class Base
{
public:
Base() { cout<<"base class constructed!"<<endl; }
~Base() { cout<<"base class desconstruct!"<<endl; }
private:
Base& operator=(const Base& rhs) { return *this;}
};
class Derived : Base
{
public:
Derived() { cout<<"derived class constructed!"<<endl; }
~Derived() { cout<<"derived class desconstructed!"<<endl; }
private:
Another an;
};
/* main中运行{ Derived deri; } 的结果是 */
/* derived class constructed! */
/* base class constructed! */
/* base class desconstruct! */
/* derived class desconstructed! */
/* 说明deri的构造过程是这样的:先执行派生类的构造函数,再执行基类的构造函数 */
/* 析构的过程是这样的:先执行积累的析构函数,再执行派生类的构造函数 */
/* Effective C++ :deafult构造函数和析构函数主要是给编译器一个地方用来设置"藏身幕后"的代码 */
/* 像是调用base classs 和 no-static成员变量的构造函数和析构函数 */
/* 在上面写一个Another类之后,在Derived类中添加一个Another的成员变量 */
/* 运行结果是: */
/* derived class constructed! */
/* This is Another's constrctor! */
/* base class constructed! */
/* base class desconstruct! */
/* This is Another's constrctor! */
/* derived class desconstructed! */
/* 了解到 Effective C++上的句话的意思了吧,并且在一个派生类中构造函数的执行过程是这样的: */
/* 先执行基类的构造函数,再执行成员变量的构造函数,最后执行自己的构造函数 */
/******************************************************************/
/* copy构造函数和copy assignment操作符 */
/* Effective C++:上面两者的编译器默认版本只是将源对象的每一个no-static成员变量拷贝到目标对象 */
template <typename T>
class NameObject
{
public:
NameObject(const char* name,const T& value);
NameObject(const std::string& name,const T& value);
private:
std::string nameValue;
T objectValue;
};
template <typename T>
NameObject<T>::NameObject(const char* name,const T& value):nameValue(name),objectValue(value)
{
}
template <typename T>
NameObject<T>::NameObject(const std::string& name,const T& value):nameValue(name),objectValue(value)
{
}
/* copy构造函数使用示例 */
/*
NameObject<int> no1("This is me",2);
NameObject<int> no2(no1);
*/
/* 注意编译器为类默认生成的copy assignment操作符的使用情况 */
/* Effective C++: 默认生成的copy assignment操作符的行为基本上*/
/* 与生成的copy构造函数如出一辙,但一般而言只有生成的代码合法且有适当的机会证明它 */
/* 有意义时,其表现才如copy构造函数,否则编译器拒绝为类生成默认的 copy assignment操作符*/
template <typename T>
class NameObject1
{
public:
//NameObject1(const char* name,const T& value);
NameObject1(std::string& name,const T& value);
private:
std::string& nameValue;
const T objectValue;
};
template <typename T>
NameObject1<T>::NameObject1(std::string& name,const T& value):nameValue(name),objectValue(value)
{
}
/* 实验结果 */
/*
std::string newDog("helly");
std::string oldDog("marker");
NameObject1<int> p(newDog,2);
NameObject1<int> s(oldDog,36);
p=s;
*/
/*
结果如下:
错误: non-static reference member ‘std::string& NameObject1<int>::nameValue’, can’t use default assignment operator|
non-static const member ‘const int NameObject1<int>::objectValue’, can’t use default assignment operator|
在这里第一次需要生成的方法‘NameObject1<int>& NameObject1<int>::operator=(const NameObject1<int>&)’ |
*/
/*
错误原因:C++不容许"让reference该指向不同的对象"
Effective C++: 如果打算在一个"内含reference成员"的class内支持赋值操作符,你自己必须定义自己的copy assignment操作符
面对"内含const的成员"的class也是一样的
*/
/* 最后一个关于copy assignment操作赋应该注意的地方是 */
/* 如果某个base class 将copy assignment操作赋声明为private */
/* 编译器将拒绝为其derived class生成copy assignment操作赋 */
/*
class Base
{
public:
Base() { cout<<"base class constructed!"<<endl; }
~Base() { cout<<"base class desconstruct!"<<endl; }
private:
Base& operator=(const Base& rhs) { return *this;}
};
class Derived : Base
{
public:
Derived() { cout<<"derived class constructed!"<<endl; }
~Derived() { cout<<"derived class desconstructed!"<<endl; }
private:
Another an;
};
int main(void)
{
Derived dir1;
Derived dir2;
dir2=dir1;
return 0;
}
结果:
错误: ‘Base& Base::operator=(const Base&)’是私有的|
错误: 在此上下文中|
附注: 在这里第一次需要生成的方法‘Derived& Derived::operator=(const Derived&)’ |
*/
/*********************************************************/
/* 条款2:若不想使用编译器自动生成的函数,就该明确拒绝 */
/*********************************************************/
/* 通常如果你不希望class支持某一特定机能,只要不声明特定的函数就行了 */
/* 但这个策略对copy构造函数和copy assignment操作符不适用,因为如果 */
/* 你自己不声明,编译器会为你自动产生 */
/* 解决方法:将copy构造函数和copy assignment操作符声明为private */
/* 明确声明一个成员函数,阻止编译器暗自创建其专属版本;将这些函数声明为 */
/* private,可以阻止别人调用它 */
/* 将成员函数声明为private而故意不去实现它,是我们的常用伎俩 */
class HomeForSale
{
public:
HomeForSale() {}
friend void useprivate(HomeForSale& homeleft,const HomeForSale& homeright)
{
homeleft=homeright;
}
private:
HomeForSale(const HomeForSale&);
HomeForSale& operator=(const HomeForSale&);
};
/*
HomeForSale home1;
HomeForSale home2(home1);
HomeForSale home3;
home3=home1;
结果:
错误: ‘HomeForSale::HomeForSale(const HomeForSale&)’是私有的|
错误: 在此上下文中|
错误: ‘HomeForSale& HomeForSale::operator=(const HomeForSale&)’是私有的|
错误: 在此上下文中|
*/
/*
friend void useprivate(const HomeForSale& homeleft,const HomeForSale& homeright)
{
homeleft=homeright;
}
错误: 将‘const HomeForSale’作为‘HomeForSale& HomeForSale::operator=(const HomeForSale&)’的‘this’实参时丢弃了类型限定
[-fpermissive]|
friend void useprivate(HomeForSale& homeleft,const HomeForSale& homeright)
{
homeleft=homeright;
}
就可以运行了
*/
/* 一种使用继承的方法来阻止copying行为 */
/* 设计一个专门为了阻止copying动作而设计的base class */
class Uncopyable
{
public:
Uncopyable() {};
~Uncopyable() {};
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator= (const Uncopyable&);
};
/* 为了阻止某类的对象被拷贝,要做的就是继承这个类 */
class HomeForSale2 : private Uncopyable
{
};
/*
HomeForSale2 home1;
HomeForSale2 home2;
home2=home1;
结果:
错误: ‘Uncopyable& Uncopyable::operator=(const Uncopyable&)’是私有的|
错误: 在此上下文中|
附注: 在这里第一次需要生成的方法‘HomeForSale2& HomeForSale2::operator=(const HomeForSale2&)’ |
*/
/***************************************************/
/* 条款3:为多态基类声明virtual析构函数 */
/***************************************************/
/* C++明确指出:当derived class对象经由一个base class指针被删除 */
/* 而该base class带着一个no-virtual 析构函数,其结果未有定义--实际 */
/* 执行时通常发生的是对象的derived部分没被销毁 */
class BaseClass
{
public:
BaseClass() {}
~BaseClass() { cout<<"This is the base class destructor!"<<endl; }
private:
};
class DerivedClass: public BaseClass
{
public:
DerivedClass() {}
~DerivedClass() { cout<<"This is the derived class destructor!"<<endl; }
private:
};
/*
BaseClass* pd= new DerivedClass();
delete pd;
结果:
This is the base class destructor!
表明只有baseclass部分被析构!
*/
/* 上述问题的解决方法:给base class一个virtual析构函数 */
class BaseClass1
{
public:
BaseClass1() {}
virtual ~BaseClass1() { cout<<"This is the base class destructor!"<<endl; }
private:
};
class DerivedClass1: public BaseClass1
{
public:
DerivedClass1() {}
~DerivedClass1() { cout<<"This is the derived class destructor!"<<endl; }
private:
};
/*
BaseClass1* pd= new DerivedClass1();
delete pd;
结果:
This is the derived class destructor!
This is the base class destructor!
两个析构函数都被执行,且先执行的是派生类的析构函数
*/
/* virtual函数和virtual析构函数之间的关系 */
/*
virtual函数的目的是容许derived class的实现得以客制化
(即每个derived class可以根据自己的需要来自定义自己继承的virtual函数)
任何class只要带有virtual函数都几乎确定应该也有一个virtual
析构函数
*/
/* 当class不企图被当作base class,令其析构函数为virtual往往是一个馊主意 */
/* 虚表和虚表指针(virtual table and virtual table point) */
/* 最好不要继承没有virtual析构函数的类:比如说各种标准容器 */
/* 使用纯虚函数定义抽象类(pure virtual) */
class Pure
{
public:
virtual ~Pure()=0;
};
Pure::~Pure()
{
}
/******************************************************/
/* 条款4:别让异常逃离析构函数 */
/******************************************************/
/* C++不喜欢析构函数吐出异常 */
/* 两个异常同时存在的情况下,程序若不是结束执行就是导致不明确的行为 */
/*
C++中的异常机制 :
异常机制提供了程序中错误检测和错误处理之间的通信,C++的异常处理包括:
1.throw表达式:错误检测部分使用这种表达式来说明遇到了不可处理的错误,也就是说,throw引发了异常条件
2.try块:错误处理部分使用它来处理异常.
try块以try关键字开始,并以一个或多个catch子句结束
3.由标准库所定义的一组异常类,用来在throw和相关的catch之间传递相关的错误信息
*/
/*
try块的通用语法格式是:
try
{
program-statements
}
catch(exception-specifier)
{
handler-statements
}
catch(exception-specifier)
{
handler-statements
}
*/
/*
try
{
int i;
cin>>i;
if(i>10)
{
throw runtime_error("This is the end of the world!");
}
else
{
throw runtime_error("This is not the end of the world!");
}
}
catch(runtime_error err)
{
cout<<err.what()<<endl;
}
上面是一段抛出异常代码的实例,当用户输入的i>10的时候,输出异常This is the end of the world!
当用户输入i<10的时候,输出异常This is not the end of the world!
*/
/* 析构函数吐出异常的实验 */
class Widget
{
public:
Widget() {}
~Widget()
{
throw runtime_error("There happens an error!");
}
};
/*
在main函数中定义下面的代码:
{
std::vector<Widget> v(10);
}
结果:
terminate called after throwing an instance of 'std::runtime_error'
what(): There happens an error
Aborted (core dumped)
原因是析构容器的第一个元素期间有一个异常被抛出,其他9个元素还是
应该被销毁,否者就会出现内存泄露.当销毁第二个元素时又会抛出异常,
这时两个异常同时发生作用;C++无法同时处理两个异常,程序若不是结束执行
就是导致不明确的行为。
*/
/* 若析构函数必须执行一个动作,且该动作会在失败时抛出异常,那该如何解决? */
class DBConnection
{
public:
DBConnection() {}
static DBConnection create();
void close();
};
DBConnection DBConnection::create()
{
return DBConnection();
}
void DBConnection::close()
{
throw runtime_error("close error.");
}
class DBConn
{
public:
DBConn() {}
~DBConn()
{
try
{
db.close();
}
catch(runtime_error err)
{
}
}
private:
DBConnection db;
};
/*
在main函数中调用先面的代码:
{
DBConn dbc;
}
结果:
terminate called after throwing an instance of 'std::runtime_error'
what(): close error.
Aborted (core dumped)
为和会出现这种情况呢?
因为DBConn的析构函数调用db.close()时会抛出异常
这是,程序会退出这个析构函数,导致内存的泄露
*/
/* 下面是避免上述问题的两个方法 */
/* 1.若close抛出异常就结束程序 */
/*
将~DBConn()调用db.close()的代码修改为下面的一段代码
~DBConn()
{
try
{
db.close();
}
catch(runtime_error err)
{
cout<<err.what()<<endl;
abort();
}
}
运行结果:
close error.
Aborted (core dumped)
如果程序遭遇了一个"于析构期间发生的错误后"无法继续执行,
“强迫结束该程序”是一个合理的选项,这样可以阻止异常从析构函数中传播出去
*/
/* 吞下因调用析构函数而发生的异常 */
/*
~DBConn()
{
try
{
db.close();
}
catch(runtime_error err)
{
// 不做任何动作
}
}
*/
/* 上述两种做法都没有什么吸引力 */
/************************************************************/
/* 条款5:绝对不要在构造和析构过程中调用virtual函数 */
/************************************************************/
class Transaction
{
public:
Transaction();
virtual void logTransaction() const = 0;
};
void Transaction::logTransaction() const
{
cout<<"Transaction: log"<<endl;
}
Transaction::Transaction()
{
logTransaction();
}
class BuyTransaction: public Transaction
{
public:
virtual void logTransaction() const;
};
void BuyTransaction::logTransaction() const
{
cout<<"Buy: log"<<endl;
}
class SellTransaction: public Transaction
{
public:
virtual void logTransaction() const;
};
void SellTransaction::logTransaction() const
{
cout<<"sell : log"<<endl;
}
/*
在main编写下面的语句:
BuyTransaction b;
结果:
Transaction: log
原因:
derived class 对象内的base class成分会在derived class自身
成分构造之前先构造妥当。base class 构造期间virtual函数绝对不会
下降到derived classes阶层。
为什么?
:当base class构造函数执行时derived class的成员变量尚未初始化
"要求使用对象内部尚未初始化的部分"是危险的代名词,C++不容许你这样做。
*/
/* 在derived class中安全初始化Base class部分的方法:*/
/*
*/
int main()
{
BuyTransaction b;
return 0;
}
#include <iostream>
#include <stdexcept>
#include <vector>
#include <cstdlib>
using namespace std;
/**************************************/
/* 条款1:c++默默编写并调用的函数 */
/**************************************/
/* default构造函数和析构和析构函数 */
class Another
{
public:
Another() { cout<<"This is Another's constrctor!"<<endl; }
~Another() { cout<<"This is Another's desconstructor!"<<endl; }
};
class Base
{
public:
Base() { cout<<"base class constructed!"<<endl; }
~Base() { cout<<"base class desconstruct!"<<endl; }
private:
Base& operator=(const Base& rhs) { return *this;}
};
class Derived : Base
{
public:
Derived() { cout<<"derived class constructed!"<<endl; }
~Derived() { cout<<"derived class desconstructed!"<<endl; }
private:
Another an;
};
/* main中运行{ Derived deri; } 的结果是 */
/* derived class constructed! */
/* base class constructed! */
/* base class desconstruct! */
/* derived class desconstructed! */
/* 说明deri的构造过程是这样的:先执行派生类的构造函数,再执行基类的构造函数 */
/* 析构的过程是这样的:先执行积累的析构函数,再执行派生类的构造函数 */
/* Effective C++ :deafult构造函数和析构函数主要是给编译器一个地方用来设置"藏身幕后"的代码 */
/* 像是调用base classs 和 no-static成员变量的构造函数和析构函数 */
/* 在上面写一个Another类之后,在Derived类中添加一个Another的成员变量 */
/* 运行结果是: */
/* derived class constructed! */
/* This is Another's constrctor! */
/* base class constructed! */
/* base class desconstruct! */
/* This is Another's constrctor! */
/* derived class desconstructed! */
/* 了解到 Effective C++上的句话的意思了吧,并且在一个派生类中构造函数的执行过程是这样的: */
/* 先执行基类的构造函数,再执行成员变量的构造函数,最后执行自己的构造函数 */
/******************************************************************/
/* copy构造函数和copy assignment操作符 */
/* Effective C++:上面两者的编译器默认版本只是将源对象的每一个no-static成员变量拷贝到目标对象 */
template <typename T>
class NameObject
{
public:
NameObject(const char* name,const T& value);
NameObject(const std::string& name,const T& value);
private:
std::string nameValue;
T objectValue;
};
template <typename T>
NameObject<T>::NameObject(const char* name,const T& value):nameValue(name),objectValue(value)
{
}
template <typename T>
NameObject<T>::NameObject(const std::string& name,const T& value):nameValue(name),objectValue(value)
{
}
/* copy构造函数使用示例 */
/*
NameObject<int> no1("This is me",2);
NameObject<int> no2(no1);
*/
/* 注意编译器为类默认生成的copy assignment操作符的使用情况 */
/* Effective C++: 默认生成的copy assignment操作符的行为基本上*/
/* 与生成的copy构造函数如出一辙,但一般而言只有生成的代码合法且有适当的机会证明它 */
/* 有意义时,其表现才如copy构造函数,否则编译器拒绝为类生成默认的 copy assignment操作符*/
template <typename T>
class NameObject1
{
public:
//NameObject1(const char* name,const T& value);
NameObject1(std::string& name,const T& value);
private:
std::string& nameValue;
const T objectValue;
};
template <typename T>
NameObject1<T>::NameObject1(std::string& name,const T& value):nameValue(name),objectValue(value)
{
}
/* 实验结果 */
/*
std::string newDog("helly");
std::string oldDog("marker");
NameObject1<int> p(newDog,2);
NameObject1<int> s(oldDog,36);
p=s;
*/
/*
结果如下:
错误: non-static reference member ‘std::string& NameObject1<int>::nameValue’, can’t use default assignment operator|
non-static const member ‘const int NameObject1<int>::objectValue’, can’t use default assignment operator|
在这里第一次需要生成的方法‘NameObject1<int>& NameObject1<int>::operator=(const NameObject1<int>&)’ |
*/
/*
错误原因:C++不容许"让reference该指向不同的对象"
Effective C++: 如果打算在一个"内含reference成员"的class内支持赋值操作符,你自己必须定义自己的copy assignment操作符
面对"内含const的成员"的class也是一样的
*/
/* 最后一个关于copy assignment操作赋应该注意的地方是 */
/* 如果某个base class 将copy assignment操作赋声明为private */
/* 编译器将拒绝为其derived class生成copy assignment操作赋 */
/*
class Base
{
public:
Base() { cout<<"base class constructed!"<<endl; }
~Base() { cout<<"base class desconstruct!"<<endl; }
private:
Base& operator=(const Base& rhs) { return *this;}
};
class Derived : Base
{
public:
Derived() { cout<<"derived class constructed!"<<endl; }
~Derived() { cout<<"derived class desconstructed!"<<endl; }
private:
Another an;
};
int main(void)
{
Derived dir1;
Derived dir2;
dir2=dir1;
return 0;
}
结果:
错误: ‘Base& Base::operator=(const Base&)’是私有的|
错误: 在此上下文中|
附注: 在这里第一次需要生成的方法‘Derived& Derived::operator=(const Derived&)’ |
*/
/*********************************************************/
/* 条款2:若不想使用编译器自动生成的函数,就该明确拒绝 */
/*********************************************************/
/* 通常如果你不希望class支持某一特定机能,只要不声明特定的函数就行了 */
/* 但这个策略对copy构造函数和copy assignment操作符不适用,因为如果 */
/* 你自己不声明,编译器会为你自动产生 */
/* 解决方法:将copy构造函数和copy assignment操作符声明为private */
/* 明确声明一个成员函数,阻止编译器暗自创建其专属版本;将这些函数声明为 */
/* private,可以阻止别人调用它 */
/* 将成员函数声明为private而故意不去实现它,是我们的常用伎俩 */
class HomeForSale
{
public:
HomeForSale() {}
friend void useprivate(HomeForSale& homeleft,const HomeForSale& homeright)
{
homeleft=homeright;
}
private:
HomeForSale(const HomeForSale&);
HomeForSale& operator=(const HomeForSale&);
};
/*
HomeForSale home1;
HomeForSale home2(home1);
HomeForSale home3;
home3=home1;
结果:
错误: ‘HomeForSale::HomeForSale(const HomeForSale&)’是私有的|
错误: 在此上下文中|
错误: ‘HomeForSale& HomeForSale::operator=(const HomeForSale&)’是私有的|
错误: 在此上下文中|
*/
/*
friend void useprivate(const HomeForSale& homeleft,const HomeForSale& homeright)
{
homeleft=homeright;
}
错误: 将‘const HomeForSale’作为‘HomeForSale& HomeForSale::operator=(const HomeForSale&)’的‘this’实参时丢弃了类型限定
[-fpermissive]|
friend void useprivate(HomeForSale& homeleft,const HomeForSale& homeright)
{
homeleft=homeright;
}
就可以运行了
*/
/* 一种使用继承的方法来阻止copying行为 */
/* 设计一个专门为了阻止copying动作而设计的base class */
class Uncopyable
{
public:
Uncopyable() {};
~Uncopyable() {};
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator= (const Uncopyable&);
};
/* 为了阻止某类的对象被拷贝,要做的就是继承这个类 */
class HomeForSale2 : private Uncopyable
{
};
/*
HomeForSale2 home1;
HomeForSale2 home2;
home2=home1;
结果:
错误: ‘Uncopyable& Uncopyable::operator=(const Uncopyable&)’是私有的|
错误: 在此上下文中|
附注: 在这里第一次需要生成的方法‘HomeForSale2& HomeForSale2::operator=(const HomeForSale2&)’ |
*/
/***************************************************/
/* 条款3:为多态基类声明virtual析构函数 */
/***************************************************/
/* C++明确指出:当derived class对象经由一个base class指针被删除 */
/* 而该base class带着一个no-virtual 析构函数,其结果未有定义--实际 */
/* 执行时通常发生的是对象的derived部分没被销毁 */
class BaseClass
{
public:
BaseClass() {}
~BaseClass() { cout<<"This is the base class destructor!"<<endl; }
private:
};
class DerivedClass: public BaseClass
{
public:
DerivedClass() {}
~DerivedClass() { cout<<"This is the derived class destructor!"<<endl; }
private:
};
/*
BaseClass* pd= new DerivedClass();
delete pd;
结果:
This is the base class destructor!
表明只有baseclass部分被析构!
*/
/* 上述问题的解决方法:给base class一个virtual析构函数 */
class BaseClass1
{
public:
BaseClass1() {}
virtual ~BaseClass1() { cout<<"This is the base class destructor!"<<endl; }
private:
};
class DerivedClass1: public BaseClass1
{
public:
DerivedClass1() {}
~DerivedClass1() { cout<<"This is the derived class destructor!"<<endl; }
private:
};
/*
BaseClass1* pd= new DerivedClass1();
delete pd;
结果:
This is the derived class destructor!
This is the base class destructor!
两个析构函数都被执行,且先执行的是派生类的析构函数
*/
/* virtual函数和virtual析构函数之间的关系 */
/*
virtual函数的目的是容许derived class的实现得以客制化
(即每个derived class可以根据自己的需要来自定义自己继承的virtual函数)
任何class只要带有virtual函数都几乎确定应该也有一个virtual
析构函数
*/
/* 当class不企图被当作base class,令其析构函数为virtual往往是一个馊主意 */
/* 虚表和虚表指针(virtual table and virtual table point) */
/* 最好不要继承没有virtual析构函数的类:比如说各种标准容器 */
/* 使用纯虚函数定义抽象类(pure virtual) */
class Pure
{
public:
virtual ~Pure()=0;
};
Pure::~Pure()
{
}
/******************************************************/
/* 条款4:别让异常逃离析构函数 */
/******************************************************/
/* C++不喜欢析构函数吐出异常 */
/* 两个异常同时存在的情况下,程序若不是结束执行就是导致不明确的行为 */
/*
C++中的异常机制 :
异常机制提供了程序中错误检测和错误处理之间的通信,C++的异常处理包括:
1.throw表达式:错误检测部分使用这种表达式来说明遇到了不可处理的错误,也就是说,throw引发了异常条件
2.try块:错误处理部分使用它来处理异常.
try块以try关键字开始,并以一个或多个catch子句结束
3.由标准库所定义的一组异常类,用来在throw和相关的catch之间传递相关的错误信息
*/
/*
try块的通用语法格式是:
try
{
program-statements
}
catch(exception-specifier)
{
handler-statements
}
catch(exception-specifier)
{
handler-statements
}
*/
/*
try
{
int i;
cin>>i;
if(i>10)
{
throw runtime_error("This is the end of the world!");
}
else
{
throw runtime_error("This is not the end of the world!");
}
}
catch(runtime_error err)
{
cout<<err.what()<<endl;
}
上面是一段抛出异常代码的实例,当用户输入的i>10的时候,输出异常This is the end of the world!
当用户输入i<10的时候,输出异常This is not the end of the world!
*/
/* 析构函数吐出异常的实验 */
class Widget
{
public:
Widget() {}
~Widget()
{
throw runtime_error("There happens an error!");
}
};
/*
在main函数中定义下面的代码:
{
std::vector<Widget> v(10);
}
结果:
terminate called after throwing an instance of 'std::runtime_error'
what(): There happens an error
Aborted (core dumped)
原因是析构容器的第一个元素期间有一个异常被抛出,其他9个元素还是
应该被销毁,否者就会出现内存泄露.当销毁第二个元素时又会抛出异常,
这时两个异常同时发生作用;C++无法同时处理两个异常,程序若不是结束执行
就是导致不明确的行为。
*/
/* 若析构函数必须执行一个动作,且该动作会在失败时抛出异常,那该如何解决? */
class DBConnection
{
public:
DBConnection() {}
static DBConnection create();
void close();
};
DBConnection DBConnection::create()
{
return DBConnection();
}
void DBConnection::close()
{
throw runtime_error("close error.");
}
class DBConn
{
public:
DBConn() {}
~DBConn()
{
try
{
db.close();
}
catch(runtime_error err)
{
}
}
private:
DBConnection db;
};
/*
在main函数中调用先面的代码:
{
DBConn dbc;
}
结果:
terminate called after throwing an instance of 'std::runtime_error'
what(): close error.
Aborted (core dumped)
为和会出现这种情况呢?
因为DBConn的析构函数调用db.close()时会抛出异常
这是,程序会退出这个析构函数,导致内存的泄露
*/
/* 下面是避免上述问题的两个方法 */
/* 1.若close抛出异常就结束程序 */
/*
将~DBConn()调用db.close()的代码修改为下面的一段代码
~DBConn()
{
try
{
db.close();
}
catch(runtime_error err)
{
cout<<err.what()<<endl;
abort();
}
}
运行结果:
close error.
Aborted (core dumped)
如果程序遭遇了一个"于析构期间发生的错误后"无法继续执行,
“强迫结束该程序”是一个合理的选项,这样可以阻止异常从析构函数中传播出去
*/
/* 吞下因调用析构函数而发生的异常 */
/*
~DBConn()
{
try
{
db.close();
}
catch(runtime_error err)
{
// 不做任何动作
}
}
*/
/* 上述两种做法都没有什么吸引力 */
/************************************************************/
/* 条款5:绝对不要在构造和析构过程中调用virtual函数 */
/************************************************************/
class Transaction
{
public:
Transaction();
virtual void logTransaction() const = 0;
};
void Transaction::logTransaction() const
{
cout<<"Transaction: log"<<endl;
}
Transaction::Transaction()
{
logTransaction();
}
class BuyTransaction: public Transaction
{
public:
virtual void logTransaction() const;
};
void BuyTransaction::logTransaction() const
{
cout<<"Buy: log"<<endl;
}
class SellTransaction: public Transaction
{
public:
virtual void logTransaction() const;
};
void SellTransaction::logTransaction() const
{
cout<<"sell : log"<<endl;
}
/*
在main编写下面的语句:
BuyTransaction b;
结果:
Transaction: log
原因:
derived class 对象内的base class成分会在derived class自身
成分构造之前先构造妥当。base class 构造期间virtual函数绝对不会
下降到derived classes阶层。
为什么?
:当base class构造函数执行时derived class的成员变量尚未初始化
"要求使用对象内部尚未初始化的部分"是危险的代名词,C++不容许你这样做。
*/
/* 在derived class中安全初始化Base class部分的方法:*/
/*
*/
int main()
{
BuyTransaction b;
return 0;
}