条款07:为多态基类声明virtual析构函数

今天看了《Effective C++》中关于 virtual 的用法,感觉在平时的使用中还是要注意一下,所以写一些东西把它记录下来。这里写的会比较简单,如果想有更深的了解推荐看原著。

多态在程序编写中是必不可少的,比如我们设计一个 TimeKeeper 作为 base class 来记录时间,派生出 derived class 作为不同的计时方法。

class TimeKeeper {
public:
    TimeKeeper();
    ~TimeKeeper();
};
class AtomicClock: public TimeKeeper { ... }; //原子钟
class WaterClock: public TimeKeeper { ... }; //水钟
class WristWatch: public TimeKeeper { ... }; //腕表

按照工厂模式的设计理念,我们设计一个函数来获取 TimeKeeper 的指针指向这个计时对象。

TimeKeeper* getTimeKeeper(); //返回一个指针,指向一个TimeKeeper派生类的动态分配对象

factory(工厂)函数有个规矩:被 getTimeKeeper() 返回的对象必须位于 Heap 中。

因此为了避免内存泄漏(很重要),每次获取 TimeKeeper 指针对象后一定要及时的delete掉。

TimeKeeper* ptk = getTimeKeeper();  //同TimeKeeper继承体系获取一个动态分配对象

...                                 //运用它
delete ptk;                         //释放它

依赖客户执行 delete 动作,基本上便带有某种错误倾向。” ——条款13

这里的问题就在于 base class(TimeKeeper)有一个 non-virtual 析构函数。getTimeKeeper返回的指针指向一个 derived class 对象(例如 AtomicClock),而那个对象却经由一个 base class 指针(例如一个 TimeKeeper* 指针)被删除。C++明白指出:

当 derived class 对象经由一个 base class 指针被删除,而该 base class 带着一个 non-virtual 析构函数,其结果未有定义——实际执行时通常发生的是对象的 derived 成分没有被销毁。

其实消除这个问题的做法也很简单:给 base class(TimeKeeper)一个 virtual 析构函数。此后删除 derived class 对象就会销毁整个对象(包括所有 derived class 成分)。

class TimeKeeper {
public:
    TimeKeeper();
    ~TimeKeeper();
};
TimeKeeper* ptk = getTimeKeeper();

...                                 
delete ptk;                         //Bingo

当然,如果 class 不包含 virtual 函数,也就意味着它并不想被用作一个 base class 。这时令其析构函数为virtual 往往是一个 bad idea!(具体细节看原著,这里不多说)

因此,许多人的心得是:只有当 class 内含至少一个 virtual 函数,才为它声明 virtual 析构函数
这也反过来提醒我们:不要试图去继承一个标准容器(不带 virtual 析构函数)或者其他任何“带有 non-virtual 析构函数”的 class!

C++其实也有类似 JAVA 里 Abstract Class ,就是令 class 带一个 pure virtual 析构函数。pure virtual 函数导致 class 不能被实例化。也就是说你不能为那种类型创建对象。

有时候你希望创建一个抽象 class ,然而手上没有任何 pure virtual 函数,怎么办?解决方法就是为你的抽象 class 声明一个 pure virtual 析构函数。

class AWOV {                        //AWOV="Abstract w/o Virtuals"
public:
    virtual ~AWOV( ) = 0;           //声明 pure virtual 析构函数
};
AWOV::~AWOV() { };                 //pure virtual 析构函数的定义

这个 class 有一个 pure virtual 函数,所以它是个抽象 class,又由于他有个 virtual 析构函数,所以不用担心析构函数的问题。

析构函数的运作方式是:最深层派生的那个 class 其析构函数最先被调用,然后是其每一个 base class 的析构函数被调用。编译器会在 AWOV 的 derived classes 的析构函数中创建一个对 ~AWOV 的调用动作,所以必须为这个函数提供一份定义。如果不这样做,连接器会抱怨的。

请记住:

1.polymorphic (带多态性质的)base classes 应该声明一个 virtual 析构函数。如果 class 带有任何virtual 函数,它就应该拥有一个 virtual 析构函数。
2.Classes 的设计目的如果不是作为 base classes 使用,或不是为了具备多态性(polymorphically),就不该声明 virtual 析构函数。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值