Effective C++读书笔记(条款30-34)

《Effective C++》 读书笔记(详细总结55条款)上篇 下面从四个方面来说 (1) C++ 以 C 为基础,很多语句语法都没有改变,只是进行了扩展,C++ 解决问题的时候,可以理解为 C 的高效解法 (2) 面向对象,有构造函数,析构函数,继承、封装、多态、虚函数动态绑定,这是不同于C 语言的部分 (3) 泛型编程、可以理解为代码的模型,但是代码本身并不占用内存空间,只有在实例化的时候,才分配内存,所以可以提高代码复用性 阅读详情

(五).实现

____________________________________________________________________________________________________________________________________

条款30:透彻了解inlining 的里里外外

#1.inline是将“对此函数的每一个调用”都以函数本体来替换之,所以inline函数
应保证函数本体的短小,这样,既可以导致较小的目标码,又可以导致较高的指令
高速缓存集中率。

#2.大多数建置环境在编译期间进行inlining,所以Inline函数通常一定被置于头文件中,
Templates通常也被置于头文件中,因为编译器要在编译期间将其具现化。

#3.一个Inline函数是否真的被inlined取决于建置环境,但主要取决于编译器。
(大多数编译器无法将你要求的函数Inline化时,会给你一个警告信息。)
(1).所有对virtual函数的调用都会使Inlining落空,因为virtual意味着到运行期
才决定调用哪个函数。
(2).编译器通常不对“通过函数指针而进行的调用“inlining,例如:
inline void f(){...}   //假设编译器有意愿inline "对f的调用”
void (*pf)()=f;           //pf指向f
...
f();                   //这个调用将被inlined,因为它是一个正常调用
pf();                   //这个调用或许不被inlined,因为它通过函数指针达成
(3).有时候编译器会生成构造函数和析构函数的副本,如此一来它们就可以获得指针
指向那些函数,在array内部元素的构造和析构中使用。
(4).Derived class 构造函数也许不被inlined,因为即便是空构造,它也会调用
base classes构造函数和进行异常安全检查,致使代码块增大,从而不适合inline.

#4.不要因为function templates 出现在头文件,就将它们声明为inline。

#5.先将inline限制在那些平淡无奇到只有一句的函数身上或干脆不inline,可以
方便日后的调试过程,不过这样也等于将自己推向手工最优化之路,但毕竟这样更
符合80-20法则。
(虽然某些建置环境勉力支持对inlined函数的调试,其他许多建置环境仅仅只能
"在调试版程序中禁止发生inlining".)

#6.inline带来的一个弊端是,一旦inline函数被修改,依靠它的客户端都必须重新
编译,毕竟inline会插入函数本体,所以请保证inline使用在短小明确的代码上,这
可为日后升级提供便利。
____________________________________________________________________________________________________________________________________
条款31:将文件间的编译依存关系降至最低
#1.标准程序库不该作前置声明,而应该使用#includes来完成目的。
理由1:标准程序库的前置声明比较复杂,实际上并不需要你这么做。
理由2:标准程序库意味着它成为了公用的标准,所以极少会做改动,从而
要求重新编译,特别是当它作为预编译头使用时,所以请放心使用#includes.

#2.支持“编译依存最小化”的一般构想是:相依于声明式,不要相依于定义式。因为
编译器对于定义式需要确定其实现的大小,以致于增加了编译依存性。
(如果可以,请让头文件尽可能自我满足,做不到则考虑声明式)
三个声明式的简单策略:
(1).如果使用 object references 或 object pointers 可以完成任务,就不要使用
objects。
(2).如果能够,尽量以 class 声明式替换 class 定义式。
//注意,当你声明一个函数而它用到某个class时,你并不需要该 class 定义;
//纵使函数以 by value 方式传递该类型的参数(或返回值):
class Date;            //Date声明式
Date today();
void clearAppointments(Date d); //Date定义式
(3).为声明式和定义式(对同一对象的说法)提供不同的头文件
(用于声明式较多时,为了组织结构的统一)
例如:
#include"datefwd.h"       //其中声明 class Date;
Date today();
void clearAppointments(Date d);
//"datefwd.h"命名方式取决于C++标准程序库文件的<iosfwd>,<iosfwd>带来的
//另一个彰显是,本条款也使用于templates,毕竟也有些建置环境允许将templates
//的定义式放在”非头文件“内,这样一来就可以将只含声明式的头文件提供给templates

#3.基于声明式的两个手段是 Handle classes 和 Interface classes。
//Handle classes示例:
#include<string>
#include<memory>
//Person.h
class PersonImpl;
class Address;
class Person{
public:
    Person(const std::string& name, const Date& birthday,
        const Address& addr);
    std::string name()const;
    std::string birthDate() const;
    std::string address() const;
    ...
private:
    std::tr1::shared_ptr<PersonImpl> pImpl;
};

//Person.cpp
#include"PersonImpl.h"
Person(const std::string& name, const Date& birthday,
    const Address& addr)
    :pImpl(new PersonImpl(name, birthday, addr))
{}
std::string Person::name() const
{
    return pImpl->name();
}
    
//Interface classes示例:
class Person{
public:
    virtual ~Person();
    virtual std::string name() const = 0;
    virtual std::string birthDay() const = 0;
    virtual std::string address() const = 0;
    static std::tr1::shared_ptr<Person>  //工厂函数(或称为virtual构造函数)
    create(const std::string& name,         //创建一个派生类对象,并返回基类指针
        const Date& birthday,
        const Address& addr);
        return std::tr1::shared_ptr<Person>(new RealPerson(name, birthday,addr));
    ...
};
class RealPerson:public Person{
public:
    RealPerson(const std::string& name, const Date& birthday,
    const Address& addr)
    :theName(name),theBirthDate(birthday),theAddress(addr)
    {}
    virtual ~RealPerson()
    std::string name() const;
    std::string birthDay() const;
    std::string address() const;
private:
    std::string theName;
    Date theBirthDate;
    Address theAddress;
};
{}
//客户可以这样使用:
std::string name;
Date dateOfBirth;
Address address;
...
//创建一个对象,支持Person接口
std::tr1::shared_ptr<Person> pp(Person::create(name, dateOfBirth, address));
...
std::cout<<pp->name(),
        <<"was born on"
        <<pp->birthDay()
        <<"and now lives at"
        <<pp->address();
...            //pp离开作用域对象会自动消除
对Handle classes和Interface classes的评价:
使用Handle classes 或 Interface classes,虽然降低了文件间的编译依存性,
但却会使代码和目标码增多,降低简洁性,另外,动态内存分配也会带来额外的
开销,并带来遭遇bad_alloc的可能性。此外,Interface classes 中virtual函数
的调用还会导致间接跳跃(indirect jump)成本,除此之外,vpr的存在也会使类
对象变大,其变大大小取决于base classes 和 dervied classes中不同的virtual
函数个数。因此,你应该以渐进式方式来考虑使用这些技术。
____________________________________________________________________________________________________________________________________

(六).继承与面向对象设计

____________________________________________________________________________________________________________________________________

条款32:确定你的public继承塑模出的is-a 关系
#1."public继承"意味着is-a。适用于base classes 身上的每一件事情一定也适用
于derived classes 身上,因为每一个derived class 对象也是一个base class
对象。
例如:
class Bird{
public:
    virtual void fly(); //鸟会飞
    ...
};
class Penguin:public Bird{ //企鹅是一种鸟
    ...
};
//这里的企鹅是一种鸟使用了public继承,
//但这里仍然有一个问题,”企鹅不会飞!“,
//而此处的继承关系却表明企鹅会飞,之所以
//出错的原因在于并不是所有的鸟类都会飞。

//我们可以更改接口使它运行期产生错误:
void error(const std::string& msg); //定义于另外某处
class Penguin:public Bird{
public:
    virtual void fly() { error("Attempt to make a penguin fly!"); }
    ...
};

//如此便可以在运行期表明,“企鹅会飞,但尝试这么做却是一种错误!”
//而好的接口应该可以防止无效的代码通过编译,因此我们应该采取
//另一种在“在编译器拒绝企鹅飞行”的设计,如下:
class Bird{
    ...
};
class FlyingBird: public Bird{
public:
    virtual void fly();
    ...
};
class Penguin: public Bird{
    ...
};
//此时,因为行为的正确合理,你让企鹅飞,编译器肯定会抱怨:
Penguin p;
p.fly(); //编译期错误

#2.public继承适合于不会对base classes 原有形态和行为产生束缚的derived class:
例如:
//考虑以下代码:
class Renctangle{
public:
    virtual void setHeight(int newHeight);
    virtual void setWidth(int newWidth);
    virtual int height() const;        //返回当前值
    virtual int width() const;
    ...
};
void makeBigger(Rectangle& r)         //这个函数用以增加r的面积
{
    int oldHeight = r.height();
    r.setWidth(r.width() + 10);        //为r的宽度增加10
    assert(r.height() == oldHeight);//判断r的高度是否未曾改变
}
//显然,上述的assert结果永远为真。因为makeBigger只改变r的宽度;r的
//高度从未改变。

//现考虑这段代码,其中使用public继承,允许正方形被视为一种矩形:
class Square: public Rectangle {...};
Square s;
...
assert(s.width() == s.height());    //这对正方形一定为真
makeBigger(s);                        //由于继承,s是一种(is-a)矩形,
                                    //所以我们可以增加其面积。
assert(s.width() == s.height());    //对所有正方形应该仍然为真。

//但我们遇到了一个问题,当makeBigger(s)之后,第二个assert就不为真了
//其原因是Square改变了base class-Rectangle的形态,对行为产生了约束,
//因为它要求了长等于宽,这也正验证了本条款的这句话:public继承适合于
//不会对base classes 原有形态和行为产生束缚的derived class

//从另一个角度来看,任何施用于base class的事情都应该施用于dervid class
//而base class要求长可以不等于宽,但dervid class却无法适应该要求,因此,
//咋看之下,正方形和长方形应该用public继承,但实则不然。
____________________________________________________________________________________________________________________________________
条款33:避免遮掩继承而来的名称
#1.C++的名称遮掩规则所做的唯一事情就是:遮掩名称。至于名称类型相不相同
并不重要。(意思是只看名称,忽略名称类型,参数类型,参数个数,等其他东西。)

#2.C++编译器遵循的名称查找规则为局部到全局。
例如,查找一个函数,其顺序为:
class->base class->内含base class的namespace(s)->global
如果在某处查找到该名称,则不会继续往下查找。

#3.derived classes内的名称会遮掩base classes内的名称。在public继承下从来
没有人希望如此。(这是#2中的一个特例)

#4.为了让遮掩的名称再见天日,可使用
(1).using声明式(使某作用域内所有该名称曝光)
(2).转交函数(forwarding functions).
(使某作用域内特定名称在另一作用域内延续)
例如:
class Base{
private:
    int x;
public:
    virtual void mf1() = 0;
    virtual void mf1(int);
    virtual void mf2();
    void mf3();
    void mf3(double);
    ...
};
class Derived:public Base{
public:
    virtual void mf1();
    void mf3();
    void mf4();
    ...
};

Derived d;
int x;
...
d.mf1();    //没问题,调用Derived::mf1
d.mf1(x);    //错误!因为 Dervid::mf1遮掩了Base::mf1
d.mf2();    //没问题,调用Base::mf2
d.mf3();    //没问题,调用Derived::mf3
d.mf3(x);    //错误!因为 Derived::mf3遮掩了Base::mf3

//【使用using声明式的方法】:
class Derived:public Base{
public:
    using Base::mf1;        //让 Base class内名为mf1 和 mf3的所有东西
    using Base::mf3;        //在 Derived 作用域内都可见(并且public)
    virtual void mf1();
    void mf3();
    void mf4();
    ...
};
//现在再看以下改变:
d.mf1();    //没问题,调用Derived::mf1
d.mf1(x);    //现在没问题,调用Base::mf1
d.mf2();    //没问题,调用Base::mf2
d.mf3();    //没问题,调用Derived::mf3
d.mf3(x);    //现在没问题,调用Base::mf3

//现假设我们唯一想要继承Base::mf1()
//因此我们可用【转交函数】的手法使其可见,
//并使用该特定手法:
class Derived:private {
public:
    virtual void mf1(){Base::mf1();} //转交函数暗自成为inline
    ...
};
Derived d;
int x;
d.mf1();    //很好,调用的是 Derived::mf1
d.mf1(x);    //错误! Base::mf1(x)被遮掩了
____________________________________________________________________________________________________________________________________
条款34:区分接口继承和实现继承
#1.接口继承和实现继承不同。在public继承之下,derived classes总是继承
base classes的接口。

#2.三种函数继承方式:
<1>.声明一个pure virtual函数的目的是为了让derived classes只继承函数接口。
(带有强制性实现含义,但其实现码具有参考意义。)
<2>.声明简朴的(非纯)impure virtual函数的目的,是让 derived classses 继承
该函数的接口和缺省实现。(可默认继承接口及缺省实现。)
<3>.声明non-virtual函数的目的是为了令derived classes继承函数的接口及一份
强制性实现。
(non-vritual函数代表的含义是其不变性凌驾于其特异性。)
//考虑以下代码:
class Shape {
public:
    virtual void draw() const = 0;    //<1>的形式
    virtual void error(const std::string& msg); //<2>的形式
    int objectID() const;    //<3>的形式
    ...
};
class Rectangle:public Shape{...};
class Ellipse:public Shape{...};

其中<1>的设计思想是:你必须提供一个draw函数,但我不干涉你怎么实现它。
其中<2>的设计思想是:你必须支持一个error函数,但如果你不想自己写一个,
可以使用Shape class提供的版本。
其中<3>的设计思想是:objectID适用于base class和任何想使用它的
derived class,如果有需要,你只要继承并使用它就好了。

#3.pure virtual函数可以实现,但调用它的唯一用途是”调用时明确指出其class
类型“,其好处是可以借助编译期明确指出的错误来避免犯下缺省继承的错误。
//考虑以下代码:
class Airport{...};
class Airplane{
public:
    virtual void fly(const Airport& destination);
    ...
};
void Airplane::fly(const Ariport& destination);
{
    //缺省实现,将飞机飞至指定的目的地
}
class ModelA:public Airplane{...};
class ModelB:public Airplane{...};

//现假设该飞机场引进了C型飞机,但此C型飞机不走默认路线,
//而是走新的航线,于是该航空公司程序员为其添加了一些代码,
//但由于一时心急,却忘了添加新的fly函数:
class ModelC:public Airplane{...}; //未声明fly函数

//但此代码编译行的通,运行也没问题,于是C型飞机仍走默认路线,
//因此便酿成了该航空公司的信用悲剧

//那如果我们改用pure virtual函数,并予以实现码呢?
//就像这样:
class Airplane{
public:
    virtual void fly(const Airport& destination)=0;
    ...
};
void Airplane::fly(const Airport& destination){
    ...
};
//那么程序员就必须为新型飞机强制型提供实现函数,
//而其实现码便成为了默认的参考版本
class ModelA:public Airplane{
public:
    virtual void fly(const Airport& destination)
    {
        Ariplane::fly(destination);
    }
}
class ModelB:public Airplane{
public:
    virtual void fly(const Airport& destination)
    {
        Ariplane::fly(destination);
    }
}
class ModelC:public Airplane{
public:
    virtual void fly(const Airport& destination);
}
void ModleC::fly(const Airport& destination)
{
    //将C型飞机按新路线开往目的地
}

//这样一来,如果程序员不为每个型号的飞机提供fly函数,
//编译器便会发出警告,从而避免犯下此类错误,虽然它降低
//一些简洁性,但却增加了一些明确性。另外,由于含有pure
//virtual的class只能成为抽象类,不能实例化,因此,它的

//使用场合也被添加了一些限制。

____________________________________________________________________________________________________________________________________

Effective C++ 条款36:绝不重新定义继承而来的 non-virtual 函数 深入解析 Effective C++ 条款36,理解为什么不应该重新定义继承而来的 non-virtual 函数,掌握静态绑定与动态绑定的本质区别,避免面向对象设计中的常见陷阱。 阅读详情

相关推荐

【绝版C++书籍】《Effective STL》读书笔记

《Effective STL》读书笔记写在前面《Effective STL》中可能过时的内容1 容器第1条:慎重选择容器类型。第2条:不要试图编写独立于容器类型的代码。第3条:确保容器中的对象拷贝正确而高效。第4条:调用empty而不是检查size()是否为0。第5条:区间成员函数优先于与之对应的单元素成员函数。第6条:当心C++编译器最烦人的分析机制。第7条:如果入容器中包含了通过new操作创建的指针,切记在容器对象析构前将delete掉。第8条:切勿创建包含auto_ptr的容器对象。第9条:慎重选择删

Elias_Liu的博客 1757

Effective C++读书笔记(26)

条款40:明智而审慎地使用多重继承 Use multiple inheritance judiciously 触及multiple inheritance (MI)(多继承)的时候,C++ 社区就会鲜明地分裂为两个基本的阵营。一个阵营认为如果single inheritance (SI)(单继承)是有好处的,multiple inheritance(多继承)一定更有好处。另一个阵营认为sing

pandawuwyj的专栏 911

Effective C++ 条款01:视 C++ 为一个语言联邦

这篇文章摘要: C++是一个由多个次语言组成的语言联邦,包括C风格过程式编程、面向对象的C++、模板元编程和STL标准库。作者通过《Effective C++》第一条指出,理解这种联邦结构是掌握C++的关键。文章详细解析了这四大次语言的核心特性和适用场景:C语言基础用于系统编程;面向对象特性适合大型架构;模板编程支持泛型和元编程;STL提供了容器和算法的高效实现。不同次语言的编程规则差异很大,混合使用时需要注意风格统一。文章通过嵌入式系统、游戏引擎等实际案例,展示了如何根据不同需求选择合适的次语言组合。理解

凡人叶枫的博客 786

virtual IsEmpty() const=0中的const有什么用?

后面加个const 表明该函数不会改名成员函数的值!该函数可以被常量对象访问(const)。 注意 加了const 与不加const的函数是两个不同的函数! 用个例子说明其区别: #include class A { public: void empty() { std::cout<<"call empty()\n"; }

xuyongbeijing2008的专栏 6961

PyCharm+QT Designer整合

CMD下使用pip安装PyQt4或者PYQT5 这里要注意,你下载的PYQT5不包含QT designer 还要:pip3 install PyQt5-tools,好像Pyqt5中将designer分离了或者查看源码:https://github.com/altendky/pyqt5-tools,编译安装 将QT Designer整合到PyCharm的External Tools中,以后就可...

mxh的博客 6414

3D-IC测试挑战与Tessent解决方案解析

3D-IC技术通过硅通孔(TSV)实现芯片垂直堆叠,是延续摩尔定律的关键路径。该技术面临三大核心挑战:KGD标准严苛化要求测试覆盖率达99.5%以上,存储器测试需兼容LPDDR/HBM等多种协议,逻辑堆叠需解决TSV互连的电气特性和时序验证问题。Mentor Tessent平台采用混合测试架构,结合压缩扫描测试(ATPG)和内建自测试(BIST)技术,实现100x测试数据压缩比和99.97%的TSV缺陷检出率。这些创新方案在移动SoC和高性能计算芯片中已获验证,测试时间缩短73%,缺陷逃逸率降低77%。随着

weixin_30621711的博客 376

《Effective C++》学习笔记——条款40

《Effective C++》学习笔记——条款40

转载和创作优秀的博客 350

健康保险费用预测:可解释机器学习在精算建模中的实战落地

健康保险费用预测是医疗AI与保险科技交叉领域的核心任务,本质是基于临床变量与社会因素对个体医疗支出进行风险量化。其技术原理需兼顾统计建模能力与监管可解释性,XGBoost+SHAP组合因支持特征归因、边际效应分析和临床可干预推演,成为保险精算场景的主流选择。该技术显著提升保费定价精度、降低偿付风险,并支撑DRG费用预警、团险核保辅助及再保险尾部风险评估等关键应用。本文聚焦真实产线中的时间序列验证、临床分层特征工程与监管红线指标(如Bias@90th、Calibration Slope),深入解析如何让模型不

weixin_33702545的博客 306

Effective C++ | 读书笔记 (三)

提前定义变量,有可能导致变量并没有使用(如中间抛异常了),而平白多了一个构造和析构成本。但是循环怎么办?// 方式AWidget w;i < n;...// 方式Bi < n;++i) {...做法A:1个构造 + 1个析构 + n个赋值操作做法B:n个构造函数 + n个析构函数打破本条款选择A的依据:(1)你知道赋值成本比“构造+析构"成本低。(2)你正在处理代码中效率高度敏感的部分。否则你应该使用做法B,维持变量尽可能在使用时定义的原则。请记住。

m0_74795952的博客 945

从Excel到‘一张图’办案:手把手教你用AbutionGraph构建公安经侦知识图谱(含数据建模避坑指南)

本文详细介绍了如何利用AbutionGraph时序图数仓技术,将公安经侦领域的Excel、银行流水等碎片化数据转化为可交互的知识图谱。通过数据清洗、实体关系模型设计、时序数据处理等步骤,实现高效智能分析,提升办案效率。特别包含数据建模避坑指南和实战案例,助力公安金融案件侦破。

weixin_33702545的博客 342

实战指南:R语言多组倾向评分逆概率加权(IPTW)建模与结果解读

本文详细介绍了如何使用R语言实现多组倾向评分逆概率加权(IPTW)建模,包括数据预处理、倾向评分估计、权重计算及结果解读。通过实战案例演示,帮助研究者掌握这一统计方法,有效平衡多组混杂因素,模拟随机对照试验效果,适用于医学、社会科学等领域的数据分析。

weixin_42528534的博客 395

《Effective C++》 读书笔记(详细总结55条款)下篇

Effective C++ 目录五、实现26、尽可能延后变量定义的时间27、尽量少做转型动作28、避免返回 Handles 指向对象内部成分29、为异常安全努力是值得的30、透彻理解 inlining 里里外外31、将文件间的编译依存关系降到最低六、继承与面向对象设计32、确定你的 public 继承塑模出is-a的关系33、避免遮掩继承而来的名称34、区分接口继承和实现继承35、考虑 virtual 函数以外的其他选择36、绝不重新定义继承而来的 non-virtual 函数七、模板与泛型编程八、定制

身在边城 心在编程 870

Android Studio中把llama.cpp编译Android .so

本文介绍了一个在Android Studio中集成llama.cpp的最小Demo实现方案,通过JNI将llama.cpp编译为Android.so库,实现本地加载GGUF模型进行文本生成。文章详细说明了项目结构配置(SDK≥30,NDK≥28)、CMake编译设置、Kotlin-JNI-C++的完整调用链实现,以及模型文件部署方式。该Demo采用每次请求新建上下文的简化设计,包含加载模型、生成文本、资源释放等核心功能,并提供了错误排查建议。项目舍弃了上下文保持等复杂功能以确保稳定性,适合作为端侧大语言模型

Zhang Phil 516

读书笔记_Effective C++_习惯C++

这是一本非常经典C++书籍,也是我在工作中发现自己C++上还有很多薄弱点的时候经常拿来充电的。这本书内容很多,讲了很多如何高效地使用C++的方法,有些地方自己也没能啃透,读过一遍后很多知识点容易忘记,这次是一条一条地进行温习,之所以会分享出来是觉得对于程序员来说,好记性不如烂笔头,自己多动手往往在真正写程序的时候能够像条件反射一样写出好的代码。慢工出细活,对待技术要有谨慎和敬畏之心。这本书推荐喜欢C

John_cdy的专栏 3194

YOLOv12创新改进 | 全网独家创新篇、小目标检测改进 | AAAI 2025 | 引入HS-FPN中的HFP和SDP创新点,从频域增强小目标特征,淘汰FPN进行升级,助力YOLOv12有效涨点

本文提出了HS-FPN(高频和空间感知特征金字塔网络),通过HFP(高频感知)模块增强小目标特征,SDP(空间依赖感知)模块捕获像素间空间依赖关系。实验在AI-TOD等小目标数据集上验证了该方法的有效性,相比FPN显著提升检测性能。文章详细介绍了HS-FPN的网络结构、核心代码实现及在YOLOv12中的应用方法,并提供多种改进版本的yaml配置文件,为小目标检测任务提供了有效的解决方案。

Ai缝合怪、助力小伙伴高效发论文 336

Python爬虫实战:抓取统计数据并生成年度对比图表详解

国家统计局网站(静态HTML页面Excel文件JSON接口(部分新版API)我们将重点演示从统计公报页面抓取数据,结合解析Excel文件,实现多种数据格式爬取处理。本文从零开始搭建了一个爬取国家统计数据并制作年度对比图表的完整流程。读者可以根据实际需求调整爬取目标,丰富数据分析维度,甚至结合机器学习模型预测未来趋势。欢迎你在评论区留言分享你的爬虫实践,或提出改进建议!

2201_76125261的博客 1000

Effective C++ | 读书笔记 (一)

这意味着,如果你在一个编译单元中依赖于另一个编译单元中的全局静态对象的初始化结果,你的程序可能会遇到未定义行为,因为那些对象的初始化次序是不确定的。在构造、析构函数中一定只会调用本类中的虚函数。原因:当基类指针(引用)指向子类对象时,如果析构对象通过delete 指针的方式,只会调用基类的析构函数,不会调用子类的析构函数。如果把这个当做是基类,会有问题,析构函数只有声明没有定义,析构函数从派生类到基类的调用时,会发生链接错误。时,先调用基类的构造函数,此时派生类还没有被构造出来,所以调用的是基类的虚函数。

m0_74795952的博客 1042

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

《Effective C++》 读书笔记 条款6-10

Effective C++ 6-10 Note 条款06:若不想使用编译器自动生成的函数,就明确拒绝 在老版的C++中,将不想自动生成的函数声明为private并且不定义 在当前版本的C++中,可以使用delete修饰符进行修饰 条款07:为多态基类声明virtual析构函数 带多态性质的基类应该声明一个虚析构函数,如果类带有任何虚函数,它就应该有一个虚析构函数 当出现基类指针或引用指向派生类对象时,如果析构函数不为虚函数,那么调用的就是静态对象的析构函数,也就是基类的析构函数,这会导致派生类的派生部分没

youyadefeng1的博客 282

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

《Effective C++》读书笔记

Effective C++Scott Meyers 屋檐下的水滴--读书笔记系列http://blog.youkuaiyun.com/dwater 导读 Introduction1.   所谓declaration,是用来将一个object、function、class或template的类型告诉编译器,它不带细节信息。所谓definition,是用来将细节信息提供给编译器。对

DWATER 3167

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Effective C++ | 读书笔记 (四)

对应条款24,这里只是模版实现。规则一致,但它们写法上有所区别了。public:...// 需要隐式转换的接口定义为非成员函数{...};// 使用// 这里会编译错误,2不能隐式转换上面只是把24条款示例改为模版实现,然而模版版本是编译不过的,因为编译器并不知道2要转换为什么。编译器推断不了模版的隐式转换。对于模版我们只能通过friend和inline特性来实现非成员函数的定义。public:...// 这里Rational是Rational<T>的简写形式,在类模版内部可以简写。

m0_74795952的博客 1104

Effective C++读书笔记(上)

Effective C++读书笔记(一到三章)

still_wtm的博客 748

《Effective C++》 读书笔记 条款26-30

Effective C++ 26-30 Note 条款26:尽可能延后变量定义式的出现时间 等到出现有意义值时再定义,避免无意义的默认构造函数(习惯使用拷贝构造函数) 条款27:尽量少做转型动作 C++提供的四种新式转型方法 宁可使用新式转型,也不要使用旧式转型。前者很容易辨别出来,而且也比较有着分门别类的职掌 如果可以,尽量避免转型,特别是在重视效率的代码中避免dynamic_casts dynamic_cast用于将一个基类转换为派生类,之所以需要它,是因为你想在一个你认为是派生类的基类对象中

youyadefeng1的博客 198

effective c++读书笔记

effective c++读书笔记一级目录二级目录三级目录Charpter 1. 让自己习惯C++条款01: 视C++为一个语言联邦条款02: 尽量以const,enum,inline替换#define条款03: 尽可能使用const条款04: 确定对象被使用前已先被初始化Charpter 2. 构造/析构/赋值运算条款05: 了解C++默默编写并调用哪些函数条款06: 若不想使用编译器自动生成的函数,就该明确拒绝条款07: 为多态基类声明virtual析构函数条款08: 别让异常逃离析构函数条款09: 绝

cwdben的博客 548
上一篇: Effective C++读书笔记(条款24-29)
下一篇: Effective C++读书笔记(条款35-40)
Beyond我爱杨
博客等级 码龄13年 36粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值