派生类

C++之多态性与虚函数

北城以北 提交于 2019-12-10 04:03:01
  面向对象程序设计中的多态性是指向不同的对象发送同一个消息,不同对象对应同一消息产生不同行为。在程序中消息就是调用函数,不同的行为就是指不同的实现方法,即执行不同的函数体。也可以这样说就是实现了“一个接口,多种方法”。   从实现的角度来讲,多态可以分为两类:编译时的多态性和运行时的多态性。前者是通过静态联编来实现的,比如C++中通过函数的重载和运算符的重载。后者则是通过动态联编来实现的,在C++中运行时的多态性主要是通过虚函数来实现的,也正是今天我们要讲的主要内容。   1.不过在说虚函数之前,我想先介绍一个有关于基类与派生类对象之间的复制兼容关系的内容。它也是之后学习虚函数的基础。我们有时候会把整型数据赋值给双精度类型的变量。在赋值之前,先把整形数据转换为双精度的,在把它赋值给双精度类型的变量。这种不同类型数据之间的自动转换和赋值,称为赋值兼容。同样的,在基类和派生类之间也存在着赋值兼容关系,它是指需要基类对象的任何地方都可以使用 公有 派生类对象来代替。为什么只有公有继承的才可以呢,因为在公有继承中派生类保留了基类中除了构造和析构之外的所有成员,基类的公有或保护成员的访问权限都按原样保留下来,在派生类外可以调用基类的公有函数来访问基类的私有成员。因此基类能实现的功能,派生类也可以。   那么它们具体是如何体现的呢 ?(1)派生类对象直接向基类赋值,赋值效果

Python - 派生类初始化父类的__init__构造函数

*爱你&永不变心* 提交于 2019-12-08 14:25:56
【 Python单继承 】 当父类的__init__构造函数中需要对数据进行初始化时, 在其派生的子类的__inti__方法中需要额外调用父类的__init__函数完成父类的初始化; class Base(): def __init__(self,character="%"): self.character = character def show(self): return self.character class Derived(Base): def __init__(self): super().__init__() self.derived_data = 99 def derived_Show(self): print(str(self.derived_data)+super().show()) class A(): def __init__(self): self.X = Derived() if __name__ == "__main__": a = A() a.X.derived_Show() 分析: 派生类如果缺少super().__init__()则报错; 当父类的__init__中没有初始化操作时(如下),派生类中可不比加对父类的初始化( 推荐添加 )。 class Base(): def __init__(self): pass def show(self):

C++面向对象程序设计学习笔记(5)

…衆ロ難τιáo~ 提交于 2019-12-07 09:14:27
派生类与继承 概念 继承允许编程者在已有类的基础上创建新的类,可以从一个或者多个已有类中继承函数和数据,并重新定义或者添加新的函数和数据,已有类称为基类或父类,新类称为派生类和子类。 声明 声明一个派生类的一般格式为: class 派生类名 : [继承方式] 基类名 { 派生类新增的数据成员和成员函数 }; 继承方式种类有 private, public ,protected ,分别为私有、公有和保护继承 若不显式地给出关键字,则默认为私有 构成 构造一个派生类包括三部分公作: 1)派生类从基类接受成员 派生类将基类除构造函数和析构函数以外的全部成员全部接收 2)调整从基类接收来的成员 调整包括两个方面 改变基类成员在派生类中的访问属性(通过继承方式实现) 对基类成员重定义(派生类的同名成员会覆盖基类中的同名成员) 3)在派生类中添加新的成员 基类成员在派生类中的访问属性 基类中的成员 在公有派生类中的访问属性 在私有派生类中的访问属性 在保护派生类中的访问属性 私有成员 不可直接访问 不可直接访问 不可直接访问 公有成员 公有 私有 保护 保护成员 保护 私有 保护 派生类对基类成员的访问规则 派生类对基类成员的访问形式主要有两种: (1)内部访问 由派生类中新增的成员函数对基类继承来的成员的访问 (2)对象访问 在派生类外部,通过派生类对象对从基类继承来的成员的访问

深度剖析C++析构函数

馋奶兔 提交于 2019-12-07 08:25:12
构造函数和析构函数在C 中意味着生命周期的开始和结束,它们的实现原理相同。由于析构函数往往还设置成虚函数,所以这里我重点介绍下C 析构函数的原理和各种场景。 一、析构函数的作用 当对象的生命周期结束时,会自动调用析构函数,以清理一些资源,比如释放内存、关闭文件、关闭数据库连接等等。 二、析构函数调用的时机 (1)基类析构 我们反汇编下查看上面代码: 从反汇编中可以看出,在对象离开它的作用域时,编译器自动给我们添加了一个析构函数调用的语句。 那我们使用new产生的对象会什么时候调用析构函数呢,这里我们把fun1里对象改成动态生成。 void fun1() { Base *base = new Base(); cout<<“fun1 over”<<endl; } 当我们不使用delete释放内存时,看反汇编的情况 此时,没有任何地方调用Base的析构函数 当我们使用delete释放对象时, void fun1() { Base *base = new Base(); delete base; cout<<“fun1 over”<<endl; } 我们反汇编结果: 这里我们看到析构函数调用了,这是因为当我们使用delete删除对象时,编译器会自动在后面添加一条调用析构函数的语句; 从这里我们也可以看书,C

析构函数与虚析构函数的用法,构造函数与析构函数调用情况

[亡魂溺海] 提交于 2019-12-07 08:23:37
析构函数的作用: 在对象撤销前做必要的“清理现场”的工作,当派生类的对象从内存中撤销时,一般先调用派生类的析构函数,再调用基类的析构函数,但是如果, 用new运算符动态生成一个派生类的堆对象,并让基类指针指向该派生类对象 ,当程序用delete运算符通过基类指针撤销派生类对象时, 系统只会执行基类的析构函数,而不执行派生类的析构函数 基类中有非虚构函数时的执行情况: #include<iostream> using namespace std; class point { public: point(){cout<<"point constructor"<<endl;} ~point(){ cout<<"executing point destructor"<<endl;} }; class circle:public point { public: circle(double r):radius(r){cout<<"circle constructor"<<endl;} ~circle(){ cout<<"executing circle destructor"<<endl;} private: double radius; }; int main() { point *p=new circle(2.0); delete p; system("pause"); } 执行结果:

《Effective C++》条款07:为多态基类声明virtual析构函数

落花浮王杯 提交于 2019-12-07 08:02:13
原因:C++明白指出,当派生类对象经由基类指针被删除,而该基类的析构函数是非virtual析构函数,执行的结果是派生类成分未被销毁。 解决方法:将base classes析构函数写为virtual析构函数。 适用范围:该规则只适用于polymorphic(带多态性)的base calsses上。这种base class的设计目的是:通过base class接口处理derived class对象。如果不是为了具备多态性,就不应该声明virtual析构函数。 virtual函数会增大类的内存大小。 来源: CSDN 作者: Simon.Y 链接: https://blog.csdn.net/sinat_38183777/article/details/81228889

Effective C++读书笔记(6)

旧城冷巷雨未停 提交于 2019-12-07 07:41:58
新年了~忙着东奔西跑3天,是时候回归正常生活了…… 条款08:别让异常逃离析构函数 Prevent exceptions from leavingdestructors C++ 不禁止但不鼓励从析构函数引发异常。考虑: class Widget { public: ... ~Widget() { ... } // 假设这里可能吐出一个异常 }; void doSomething() { std::vector<Widget> v; ... } // v在这里被自动销毁 当 vector v 被析构时,它有责任析构它包含的所有 Widgets。但假设在那些调用期间,先后有两个Widgets抛出异常,对于 C++ 来说,这太多了。在两个异常同时存在的情况下,程序若不是结束执行就是导致不明确行为。在本例中将导致不明确行为,使用标准库的任何其他容器(如list,set)或TR1的任何容器甚至array,也会出现相同情况。C++ 不喜欢析构函数吐出异常。 如果你的析构函数需要执行一个可能失败而抛出一个异常的操作,该怎么办呢?假设使用一个class负责数据库连接,为了确保客户不会忘记在 DBconnection对象上调用 close(),一个合理的想法是创建一个用来管理DBConnection资源的类,并在其析构函数中调用close: class DBConn { //

构造函数与析构函数中不调用虚函数

僤鯓⒐⒋嵵緔 提交于 2019-12-07 07:37:13
本文参考《effective C++》第九条款 在C++中,提倡不能在构造函数和析构函数中调用虚函数。 这是为什么呢? 首先,我们先回顾一下C++虚函数的作用。 虚函数的引入是c++运行时多态的体现,通过调用虚函数可以在运行程序时实现动态绑定,体现了面向对象编程多态的思想。 那为何提倡不能在构造函数与析构函数中不能调用虚函数。接下来我们通过代码分析在构造函数或者虚构函数中调用虚函数是否可行。 假设我们有两种商品A, B。 我们要记录着两种商品的销售记录,每当销售一种商品时,我们就要记录下来。 class item { public: item(); virtual void saleRecord() const= 0 ; //销售记录,纯虚函数 ... }; item::item() { ... virtual void saleRecord(); ... } class itemA : public item { public: itemA(); virtual void saleRecord(); ... }; class itemB : public item { public: itemB(); virtual void saleRecord(); ... }; 我们执行如下代码: itemB b; 一个derived class B 对象会被创建,

C++中基类的析构函数为什么要用virtual虚析构函数

倾然丶 夕夏残阳落幕 提交于 2019-12-07 07:29:33
知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定。 关于动态绑定的讲解,请参阅: C++中的动态类型与动态绑定、虚函数、多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是为了防止内存泄漏。具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放。假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数。那么在这种情况下,派生类中申请的空间就得不到释放从而产生内存泄漏。所以,为了防止这种情况的发生,C++中基类的析构函数应采用virtual虚析构函数。 示例代码讲解 现有Base基类,其析构函数为非虚析构函数。Derived1和Derived2为Base的派生类,这两个派生类中均有以string* 指向存储其name的地址空间,name对象是通过new创建在堆上的对象,因此在析构时,需要显式调用delete删除指针归还内存,否则就会造成内存泄漏。 class Base { public: ~Base() { cout << "~Base()" << endl; } }; class Derived1 : public Base { public: Derived1():name_(new string("NULL")) {} Derived1(const

《Effective C++》学习笔记条款07 为多态基类声明virtual析构函数

十年热恋 提交于 2019-12-07 07:24:42
条款 07 :为多态基类声明 virtual 析构函数 当基类的指针指向派生类的对象的时候,当我们使用完,对其调用 delete 的时候,其结果将是未有定义 —— 基类 成分通常会被销毁,而派生类的充分可能还留在堆里。这可是形成资源泄漏、败坏之数据结构、在调试器上消费许多 时间。 消除以上问题的做法很简单:给基类一个 virtual 析构函数。此后删除派生类对象就会如你想要的那般。 任何类只要带有 virtual 函数都几乎确定应该也有一个 virtual 析构函数。 如果一个类不含 virtual 函数,通常表示它并不意图被用做一个基类,当类不企图被当做基类的时候,令其析构函 数为 virtual 往往是个馊主意。因为实现 virtual 函数,需要额外的开销( 指向虚函数表的指针 vptr )。 STL 容器都不带 virtual 析构函数,所以最好别派生它们。 请记住: (1) 带有多态性质的基类应该声明一个virtual析构函数。如果一个类带有任何virtual函数,它就应该拥个 virtual 析 构 函数。 (2) 一个类的设计目的不是作为基类使用,或不是为了具备多态性,就不该声明virtual析构函数。 2013.11.28 下午 来源: CSDN 作者: ccwRadar 链接: https://blog.csdn.net/A09211008/article