首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

C++核心准则​讨论:将析构函数设为公共和虚拟,或受保护和非虚拟

析构函数应该是虚函数吗?也就是说,是否应该允许通过指向指针进行销毁?如果是,则base析构函数必须是公共才能被调用,否则虚拟调用它会导致未定义行为。...这种情况导致较早编码标准对所有析构函数都必须是虚拟提出了全面的要求。这太过分了(即使是常见情况);相反,规则应该是当且仅当析构函数是公共时,才将它们虚函数化。...析构可以看作只是另一种操作,尽管具有使非虚调用变得危险或错误特殊语义。因此,对于析构函数,选择是根据是否允许通过指向Base指针实际上调用它。“非虚”不是一种选择。...因此,如果可以调用(即是公共析构函数,则它是虚拟,否则是非虚拟。...注意,NVI模式不能应用于析构函数,因为构造函数和析构函数无法进行深度虚拟调用。(请参阅第39和55条。)

1.1K20

从零开始学C++之继承(二):继承与构造函数、派生转换

一、不能自动继承成员函数 构造函数(包括拷贝构造函数) 析构函数 =运算符 二、继承与构造函数 构造函数不被继承,派生中需要声明自己构造函数。...声明构造函数时,只需要对本类中新增成员进行初始化,对继承来成员初始化调用构造函数完成(如果没有给出则默认调用默认构造函数)。...派生构造函数需要给构造函数传递参数 #include  using namespace std; class ObjectB { public:     ObjectB...从输出可以看出: 派生对象构造次序: 先调用对象成员构造函数,接着是构造函数,然后是派生对象成员构造函数,最后是派生自身构造函数。...初始化列表参数多个且其中有调用构造函数时,先执行构造函数(从最远开始,如果多重继承则按继承顺序);其他对象成员若不止一个,则按定义顺序构造,与初始化列表顺序无关。

1.5K00
您找到你想要的搜索结果了吗?
是的
没有找到

C++编程经验(2):做虚析构函数必要性

这个要提一下,如果记不住就记住:如果不做虚析构函数,会有内存泄漏 解释 定义一个指针p,在delete p时,如果析构函数是虚函数,这时只会看p所赋值对象,如果p赋值对象是派生对象,...就会调用派生析构函数;如果p赋值对象是对象,就会调用析构函数,这样就不会造成内存泄露。...如果析构函数不是虚函数,在delete p时,调用析构函数时,只会看指针数据类型,而不会去看赋值对象,这样就会造成内存泄露。 多少学点设计模式就清楚了。...接下来是一个子类 class Inherit :public Base{ //此处省去,一切从简 }; //重点看调用 int main() { Base *p = new Inherit; //这种方式调用

55810

C++核心准则C.35:析构函数要么是公开函数,要么是保护非虚函数

C.35: A base class destructor should be either public and virtual, or protected and nonvirtual 析构函数要么是公开函数...为了避免无定义行为。如果析构函数是公有的,那么调用侧代码就会尝试使用指针销毁派生对象,在析构函数非虚函数时其结果时没有定义。...如果析构函数时保护,那么调用侧代码就无法通过类型指针销毁派生对象,这是析构函数就没有必要一定是虚函数。析构函数是保护而不是私有的,这样派生析构函数才能调用它。...通常,设计者不会知道在析构函数中应该执行什么样动作。...我们可以想象一种需要保护函数析构函数情况:当希望允许派生对象(只有这个类型)通过指针销毁另外一个对象(不是它自己)时。但是我们还没有在实际开发中遇到这种情况。

1K20

C++进阶-继承

C++进阶-继承 零、前言 一、继承概念和定义 二、和派生对象赋值转换 三、继承中作用域 四、派生默认成员函数 五、继承和友元 六、继承和静态成员 七、菱形继承和虚拟继承 八、继承和组合...;如果没有默认构造函数,则必须在派生构造函数初始化列表阶段显示调用 注:默认构造函数:无参构造函数,编译器自动生成构造函数,全缺省构造函数 示图:无默认构造函数,且不显示调用 派生拷贝构造函数必须调用拷贝构造完成拷贝初始化...注:如果不调用,系统会自动调用父默认构造函数 示图: 注:调用拷贝构造用了切片操作 派生operator=必须要调用operator=完成复制 注:这里调用赋值同样也是切片操作...:一般不自行去主动调用析构函数,不然可能会造成错误 派生对象初始化先调用构造再调派生构造 派生对象析构清理先调用派生析构再析构 示图: 五、继承和友元 概念:...将该类构造函数访问权限设置私有,当派生调用构造函数时,会先调用父构造函数,而父构造函数不能被调用,无法构造对象也就构造不了派生对象(但这样不仅派生无法构造,该类自己也不能构造

42850

【C++】构造函数初始化列表 ② ( 构造函数 初始化列表 传递参数 | 嵌套情况下 构造函数 析构函数 执行顺序 )

一、构造函数 初始化列表 传递参数 1、构造函数参数传递 构造函数 初始化列表 还可以使用 构造函数参数 ; 借助 构造函数参数列表 , 可以为 初始化列表 传递参数 ; 在下面的代码中...int heightOfA) : m_age(age), m_a(ageOfA, heightOfA) {} m_age(age) 表示 m_age 成员变量 赋值 构造函数参数中 age 参数..., A 定义了 2 个参数 有参构造函数 ; B 定义了 无参构造函数 , 但是在该 无参构造函数 中 , 定义了函数列表 B() : m_age(10), m_a(10, 150) , 在该函数列表中..., 执行了 A 构造函数 ; B 中还定义了 有参构造函数 , 接收 3 个参数 , 分别作为 m_age 成员值 , 和 A 类型成员对象 有参构造函数 2 个参数 , 这是 使用了...: 析构函数构造函数 执行顺序 相反 ; 2、代码示例 - 构造函数执行顺序 下面的代码中 , 在 B 中定义 A 类型 成员变量 ; 执行构造函数时 , 先调用 A 构造函数 , 再调用

18630

【C++修炼之路】15.C++继承

4.1 派生构造函数 4.2 派生拷贝构造函数 4.3 派生赋值运算符重载 4.4 派生析构函数 4.5 总结 五.继承与友元 六.继承与静态成员 6.1 静态成员 6.2 确定是否解引用...发现顺序: 构造构造,派生构造。 析构: 派生先析构,后析构。 4.5 总结 派生构造函数必须调用构造函数初始化那一部分成员。...如果没有默认构造函数,则必须在派生构造函数初始化列表阶段显示调用。 派生拷贝构造函数必须调用拷贝构造完成拷贝初始化。...因为这样才能保证派生对象先清理派生成员再清理成员顺序。 派生对象初始化先调用构造再调派生构造。 派生对象析构清理先调用派生析构再析构。...,因此下面打开内存窗口观察: 整体都作为D数据,D继承了A、B、C,由于菱形继承代码冗余,发现B和C继承下来A都存在在D中,而虚拟继承为了解决两个A同时出现,采用了以下策略:(下面改成虚拟继承代码

50800

【C++】继承

答案是错误,因为构成重载函数前提是必须在同一作用域,和派生是两个不同域,所以并不构成重载,而是构成隐藏。...派生构造函数只能调用构造函数来初始化那部分成员,不能在自己构造函数里面初始化成员,值得注意是,如果有默认构造函数,那我们不需要管成员初始化工作,只要把派生自己成员在构造函数里面初始化即可...但如果没有合适默认构造,那则必须在派生初始化列表显示调用有参构造函数进行成员初始化。 2....拷贝构造函数构造不同,必须在派生拷贝构造初始化列表处显示调用拷贝构造,完成成员复制。在传参时有人可能会有疑问,调用拷贝构造该如何将子类中成员提取出来呢?...构造,两次析构,其实是因为我们显示调用了Person析构,编译器自己会自动调用析构,所以2次 // 子类先析构,父后析构。

63910

关于vtordisp知多少?

字节偏移处,使用了4个字节存储了虚Basevtordisp。...MSDN给出解释是:虚继承中派生重写了函数,并且在构造函数或者析构函数中使用指向指针调用了函数,编译器会为虚添加vtordisp域。...然而,经过VS2010测试,我们发现上述示例代码便会产生vtordisp字段!条件是。 1. 派生重写了虚函数。 2. 派生定义了构造函数或者析构函数。...,它所解决问题是:由于对虚拟置换与对其派生置换之间有差异,可能会向虚函数传递错误 this 指针。 该解决方案向各个虚拟提供称作 vtordisp 字段单个构造置换调整。...曾经我遇到过一个虚拟继承实例,在对象初始化过程中会修改vtordisp字段,但是每次在初始化结束前都会把vtordisp减去一个常量使得它最终结果0。而且没有出现任何访问该字段汇编指令!

77290

C++之继承

private成员在派生中是不能被访问,如果成员不想在外直接被访问,但需要在派生中能访问,就定义protected。可以看出保护成员限定符是因继承才出现。 3....下面是这几个成员函数应该注意几个点: 1. 派生构造函数必须调用构造函数初始化那一部分成员。如果没有默认构造函数,则必须在派生构造函数初始化列表阶段显示调用。 2....派生拷贝构造函数必须调用拷贝构造完成拷贝初始化。 3. 派生operator=必须要调用operator=完成复制。 4....派生析构函数会在被调用完成后自动调用析构函数清理成员。因为这样才能保证派生对象先清理派生成员再清理成员顺序。 5. 派生对象初始化先调用构造再调派生构造。 6....派生对象析构清理先调用派生析构再析构。

9210

C++之继承

继承后父成员(成员变量+成员函数)都变成子类一部分,子类复用了成员。 2.定义 1.格式 2.继承关系和访问限定符 继承方式和访问限定符所使用关键字是一样,但他们功能不同。...当派生中定义与父类同名成员时,派生将屏蔽对该成员直接访问,称这种情况隐藏。而派生同名成员是对成员重写/重定义。...fun函数并不构成重载,因为他们在不同作用域,他们是隐藏关系 四、派生默认成员函数 1.构造函数 派生构造函数必须调用构造函数初始化那一部分成员,如果没有默认构造函数,派生就必须在初始化列表处显示调用构造函数...派生对象初始化时,会先调用构造函数,再调用派生构造函数。 2.拷贝构造 必须调用拷贝构造完成部分拷贝构造。...编译器会对析构函数函数名进行特殊处理,即派生析构函数名都会被处理destructor()。因此派生析构函数回构成隐藏。

38810

中承上启下角色——继承

这里体现出了 Student和Teacher复用了Person成员。下面我们使用监视窗口查看Student和Teacher对象,可 以看到变量复用。调用Print可以看到成员函数复用。...派生构造函数必须调用构造函数初始化那一部分成员。如果没有默认 构造函数,则必须在派生构造函数初始化列表阶段显示调用。 2....派生拷贝构造函数必须调用拷贝构造完成拷贝初始化。 3. 派生operator=必须要调用operator=完成复制。 4....派生析构函数会在被调用完成后自动调用析构函数清理成员。因为这样才能 保证派生对象先清理派生成员再清理成员顺序。 5. 派生对象初始化先调用构造再调派生构造。...派生对象析构清理先调用派生析构再析构。 7. 因为后续一些场景析构函数需要构成重写(多态中一种父子成员函数关系),重写条件之一是函数名相同(重写条件之一隐藏条件)。

71930

《挑战30天C++入门极限》图文例解C++多重继承与虚拟继承

,C++允许一个派生指定多个,这样继承结构被称做多重继承。...float tonnage) :Vehicle(weight),Car(weight,aird),Boat(weight,tonnage) //多重继承要注意调用构造函数...AmphibianCar获得了来自两个SetWeight()成员函数,当我们调用a.SetWeight(3)时候计算机不知道如何选择分别属于两个被重复拥有了成员函数SetWeight()...由于这种模糊问题存在同样也导致了AmphibianCar a(4,200,1.35f);执行失败,系统会产生Vehicle”不是或成员错误。   ...以上面的代码例,我们要想让AmphibianCar既获得一个Vehicle拷贝,而且又同时共享用Car与Boat数据成员与成员函数就必须通过C++所提供虚拟继承技术来实现。

39710

【C++】万字一文全解【继承】及其特性__(20)

之间关系可以用 继承,可以用组合,就用组合 [1]白箱复用——继承 继承允许你根据实现来定义派生实现。这种通过生成派生复用通常被称 白箱复用(white-box reuse)。...派生构造函数必须调用 构造函数初始化那一部分成员。如果没有默认构造函数,则必须在派生构造函数初始化列表阶段显示调用。...派生拷贝构造函数必须调用 拷贝构造完成拷贝初始化。 派生operator=必须要调用 operator=完成复制。...派生析构函数会在被调用完成后自动调用 析构函数清理成员。因为这样才能 保证派生对象先清理派生成员再清理成员顺序。 派生对象初始化先调用 构造再调派生构造。...派生对象析构清理先调用派生析构再 析构。 因为后续一些场景析构函数需要构成重写,重写条件之一是函数名相同(多态条件)。

11910

C++中继承

_name; // 姓名 }; ⭐1.派生构造函数必须调用构造函数初始化那一部分成员。...如果没有默认构造函数,则必须在派生构造函数初始化列表阶段显示调用。...如下图中,构造函数不是默认,因此需要派生中写出构造函数,并且在初始化列表中去调用构造函数。 ⭐2.派生拷贝构造函数必须调用拷贝构造完成拷贝初始化。...如果非要去显示调用的话,可能会出现对同一空间析构了两次情况。因为在派生析构函数中析构了一次,然后到时候,析构函数又调用了一次,这样就会报错!...派生对象析构清理先调用派生析构再析构。 继承与友元 一句话:友元关系不能继承,也就是说友元不能访问子类私有和保护成员。

92830

C++终结

由于任何派生对象在创建时候,都必需在派生构造函数中调用父构造函数。所以,只要构造函数在子类中无法被访问,那么就阻止了该类被继承,实现终结。...如果将一个构造函数声明为私有(private),可以阻止该类进一步派生,但是该类也无法直接实例化了,此方法行不通。注意,构造函数private,无法直接实例化,但是可以被间接实例化。...一个如果被虚拟继承,那么在创建它孙子类对象时,该构造函数需要单独被调用。此时,如果该构造函数在孙子类构造函数中无法访问,那么就实现了子类不能被继承。...将它默认构造函数访问权限设定为protected,这样它自身不能产生任何实例,只能用作。...任何成员函数所访问,导致编译错误

50220

C++实现不能被继承——终结

注意,构造函数private,无法直接实例化,但是可以被间接实例化。间接实例化方法是:中定义一个公有的静态成员函数,由这个函数来完成对象初始化工作。...一个如果被虚拟继承,那么在创建它孙子类对象时,该构造函数需要单独被调用。此时,如果该构造函数在孙子类构造函数中无法访问,那么就实现了子类不能被继承。...利用虚拟继承这种特性,我们可以设计出这样一个FinalParent,它不定义任何数据成员,这样任何从它派生并不会增加任何空间上开销。...将它默认构造函数访问权限设定为protected,这样它自身不能产生任何实例,只能用作。...任何成员函数所访问,导致编译错误

1.7K20

继承

这里体现出了Student和Teacher复用了Person成员。 //下面我们使用监视窗口查看Student和Teacher对象,可以看到变量复用。调用Print可以看到成员函数复用。...private成员在派生中是不能被访问,如果成员不想在外直接被访问,但需要在派生中能访问,就定义protected。可以看出保护成员限定符是因继承才出现。...派生构造函数必须调用构造函数初始化那一部分成员。...如果没有默认构造函数,则必须在派生构造函数初始化列表阶段显示调用。 派生拷贝构造函数必须调用拷贝构造完成拷贝初始化。...因为这样才能保证派生对象先清理派生成员再清理成员顺序。 派生对象初始化先调用构造再调派生构造。 派生对象析构清理先调用派生析构再析构。 ? ?

75820

C++中继承

派生构造函数必须调用构造函数初始化那一部分成员。如果没有默认构造函数,则必须在派生构造函数初始化列表阶段显示调用。...派生拷贝构造函数必须调用拷贝构造完成拷贝初始化。 派生operator=必须要调用operator=完成复制。...派生析构函数会在被调用完成后自动调用析构函数清理成员。因为这样才能保证派生对象先清理派生成员再清理成员顺序。 派生对象初始化先调用构造再调派生构造。...派生对象析构清理先调用派生析构再析构。 因为后续一些场景析构函数需要构成重写,重写条件之一是函数名相同(这个我们后面会讲解)。...B对象,首先调用了A构造函数,然后调用B构造函数,析构函数则是先调用B析构函数,然后再调用A析构函数 继承与友元 友元关系不能继承,也就是说友元不能访问子类私有和保护成员 例如下面这段代码

7610

【C++】从零开始认识继承

但是我们写了一个Person全缺省构造函数,这里就会在没有传参时候没有默认构造函数匹配,这时派生Student就会报错: 为了避免这样错误,我们可以增添派生Student构造函数...总结 派生默认成员函数注意事项: 派生构造函数必须调用构造函数初始化那一部分成员。如果没有默认构造函数,则必须在派生构造函数初始化列表阶段显示调用。...派生拷贝构造函数必须调用拷贝构造完成拷贝初始化。 派生operator=必须要调用operator=完成复制。...派生析构函数会在被调用完成后自动调用析构函数清理成员。因为这样才能保证派生对象先清理派生成员再清理成员顺序。 派生对象初始化先调用构造再调派生构造。...派生对象析构清理先调用派生析构再析构。 因为后续一些场景析构函数需要构成重写,重写条件之一是函数名相同(这个我们后面会讲解)。

5110
领券