Effective c++ 第二章总结

本文探讨了C++中构造函数与析构函数的重要概念,包括默认生成的函数、复制构造函数、赋值操作符的正确实现方法,以及如何避免常见的陷阱如异常逃逸和不当调用虚函数等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

5.了解C++默默编写并调用哪些函数。
当你定义一个空类,c++默认会给你加上一些函数,但是惟有当这些函数被需要(被调用),它们才会被编译器创建出来。如下:
class CEmpty{};
相当于:
class CEmpty
{
public:
CEmpty(){..}
CEmpty(const CEmpty& rhs){...}
~CEmpty(){...}//编译器产出的析构函数没有virtual,除非基类析构函数带有virtual


CEmpty& operator=(const CEmpty& rhs){...}
};


至于copy构造函数和copy赋值操作符,编译器创建的版本只是单纯地将来源对象的每一个non-static成员变量拷贝到目标对象。


如果你打算在一个“内含引用成员”或者“内含const成员”的类内支持赋值操作,你必须自己定义 赋值操作符函数,更改引用和const
变量是不合法的。
如果基类将赋值操作符函数或者复制构造函数声明为private,编译器不会为派生类声明赋值操作符函数和复制构造函数。


6.若不想使用编译器自动生成的函数,就该明确拒绝。
如果要想让类禁用 复制构造 和 赋值操作,则必须将 “复制构造函数”和“赋值操作函数”声明为private,并且不能实现它。
例:
class HomeForSale
{
public:
...
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
{...};


总结:为驳回编译器自动提供的机能,可将相应的成员函数声明为private并且不予实现,使用像Uncopyable这样的base class也是一种做法。


7.为多态基类声明virtual析构函数
c++明确指出,当derived class 对象经由一个base class 指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义--实际
执行时通常发生的是对象的derived成分没有被销毁。于是造成一个诡异的“局部销毁”对象,形成资源泄漏,数据破坏。
任何 class 只要带有virtual函数都几乎确定应该也有一个virtual析构函数。
如果class 不含virtual函数,通常表示它并不意图被用做一个base class.
如果一个类没有虚函数,你可以把这个类当成结构体使用,但是如果有虚函数,就会有一个虚函数表指针,这样就不能单纯的当一个结构体使用了。
如果想声明一个


总结:
a.带多态性质的base classes应该声明一个virtual析构函数。如果class带有任何virtual函数,就应该拥有一个virtual析构函数。
b.classes的设计目的如果不是作为base classes使用,或不是为了具备多态性,就不该声明virtual析构函数。




8.别让异常逃离析构函数。
析构函数如何处理异常的例子:
class DBConnection
{
public:
...
static DBConnection create();//这个函数返回DBConnection对象
void close();
};


class DBConn //这个class用来管理DBConnection对象
{
public:
...
~DBConn() //确保数据库连接总是会被管理
{
db.close();
}
private:
DBConnection db;
};


DBConn dbc(DBConnection::create());//dbc被析构会关闭数据库连接


异常处理的几种不同方式:
DBConn::~DBConn()
{
try{db.close}
catch(...)
{
...
std::abort();
}
}


DBConn::~DBConn()
{
try{db.close();}
{
...
}
}


class DBConn
{
public:
...
void close()
{
db.close();
closed=true;
}
~DBConn()
{
if(!closed)
{
try
{
db.close();
}
catch(...)
{...}
}
}
};


总结:
a.析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕获任何异常,然后吞下它们或结束程序。
b.如果客户需要对某个操作函数运行期间抛出异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该函数。




9.绝不在构造和析构过程中调用virtual函数。
总结:在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层)


10.令operator=返回一个reference to *this。
11.在operator=中处理“自我赋值”。
Widget& Widget::operator=(const Widget& rhs)
{
if(this!=&rhs)
{
delete pb;
pb=new Bitmap(*rhs.pb)
}
return *this;
}


12.复制对象时勿忘记其每一个成分。
任何时候只要你承担起“为derived class撰写copying函数”的重责大任,必须很小心地也复制其base class成分。
Customer为基类 PriorityCustomer为派生类。
PriorityCustomer::PriorityCustomer(const PriorityCustomer &rhs)
:Customer(rhs),
priority(rhs.priority)
{
...
}


PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
Customer::operator=(rhs);
priority=rhs.priority;
return *this;
}


总结:
a.copying函数应该确保复制“对象内的所有成员变量”及“所有base class成分”。
b.不要尝试以某个copying函数实现另外一个copying函数。应该将共同机能放进第三个函数中,并由两个copying函数共同调用。
内容概要:本文档详细介绍了Analog Devices公司生产的AD8436真均方根-直流(RMS-to-DC)转换器的技术细节及其应用场景。AD8436由三个独立模块构成:轨到轨FET输入放大器、高动态范围均方根计算内核和精密轨到轨输出放大器。该器件不仅体积小巧、功耗低,而且具有广泛的输入电压范围和快速响应特性。文档涵盖了AD8436的工作原理、配置选项、外部组件选择(如电容)、增益调节、单电源供电、电流互感器配置、接地故障检测、三相电源监测等方面的内容。此外,还特别强调了PCB设计注意事项和误差源分析,旨在帮助工程师更好地理解和应用这款高性能的RMS-DC转换器。 适合人群:从事模拟电路设计的专业工程师和技术人员,尤其是那些需要精确测量交流电信号均方根值的应用开发者。 使用场景及目标:①用于工业自动化、医疗设备、电力监控等领域,实现对交流电压或电流的精准测量;②适用于手持式数字万用表及其他便携式仪器仪表,提供高效的单电源解决方案;③在电流互感器配置中,用于检测微小的电流变化,保障电气安全;④应用于三相电力系统监控,优化建立时间和转换精度。 其他说明:为了确保最佳性能,文档推荐使用高质量的电容器件,并给出了详细的PCB布局指导。同时提醒用户关注电介质吸收和泄漏电流等因素对测量准确性的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值