首页 > C++基础知识(二)

C++基础知识(二)

八、

      继承:让某个类的对象获得另一个类的对象的特性。通过继承可实现代码重用,即从已存在的类派生出的一个新类将自动具有原来那个类的特性。

      类的继承还具有:(1)单向性;A类为B类的基类(父类),则派生类(子类)B继承了父类A中的属性和方法,在B类中可访问A类的属性和方法,但在父类A中则不能访问子类的任何属性和方法。同时单向又体现为子类B继承了父类A,则A类不能再继承B类。(2)传递性;A类为B类的基类,B类为C类的基类,则基类A中的属性和方法通过子类B同时又传给了子类C,同理C类也不能作为A类的基类。(3)可重用性;通过继承,基类代码得到重用,而不用重写。

      C++规定派生类中对象成员(其它类的对象)初值的设定应在初始化列表中进行,所以派生类的构造函数定义(派生类头文件中构造函数的声明格式与普通类相同)可写成:函数类型 派生类名::派生类名(形参表):基类1(参数表),基类2(参数表),...,基类n(参数表),对象成员1(参数表),对象成员2(参数表),...,对象成员n(参数表) {...}

      在派生类数据成员通常有3类:继承于基类的数据成员派生类中自身定义的数据成员以及派生类中其它类的对象。在上述形式中,由于基类在派生类中常常是隐常的,所以通过调用基类构造函数来对基类的数据成员初值化,这也称为基类拷贝或基类子对象。在上述构造函数定义中的对象成员为派生类中定义的其它类的对象(构造函数中的形参初始化)

      当然在初始化列表中也可对派生类自身数据成员初始化,但必须为“数据成员名(参数表)”形式。对于基类拷贝成员的初始化次序,若为单继承,优先初始化上层类的对象;若为多继承,则取决于派生类声明指定继承时的基类的先后次序,与初始化列表中的次序无关。对于派生类自身数据成员的初始化次序与初始化列表中的次序无关,取决于在派生类中声明的先后次序。

继承方式:公有继承(public),私有继承(private),保护继承(protected)

公有继承

       基类对象可访问基类公有成员,不可访问保护成员和私有成员。

       派生类成员可访问基类的公有成员和保护成员,它们作为派生类的成员时,保持原来的状态;若在派生类中有同名成员存在,则访问基类成员时,基类成员名前面必须加上“基类名::”来指定成员所属的类;派生类成员不可访问基类的私有成员。

       派生类对象只能访问基类的公有成员,不可访问保护成员和私有成员;对于同名成员,在基类成员名前面加上“基类名::”来指定成员所属的类,如OB.OA::m或OB-> OA::m。

       总之,公有继承时,基类对象与派生类对象可访问基类的公有成员,而派生类的成员函数则可访问基类的公有成员和保护成员。

私有继承

       基类对象可访问基类公有成员,不可访问保护成员和私有成员。

       派生类成员可访问基类的公有成员和保护成员,它们作为派生类的成员时,作为派生类的私有成员,因此不能被这个派生类的子类所访问;若在派生类中有同名成员存在,则访问基类成员时基类成员名前面必须加上“基类名::”来指定成员所属的类;派生类成员不可访问基类的私有成员。

       派生类对象不能访问基类任何成员(公有成员也不能访问)。

       总之,私有继承时,基类对象可访问基类公有成员,派生类对象不能访问基类所有成员,而派生类的成员函数则可访问基类的公有成员和保护成员(但不能再往下继承)。

保护继承

       基类对象可访问基类公有成员,不可访问保护成员和私有成员。

       派生类成员可访问基类的公有成员和保护成员,它们作为派生类的成员时,作为派生类的保护成员(与私有继承的唯一区别),且不能被这个派生类的子类所访问;若在派生类中有同名成员存在,则访问基类成员时基类成员名前面必须加上“基类名::”来指定成员所属的类;派生类成员不可访问基类的私有成员。

       派生类对象不能访问基类任何成员(公有成员也不能访问)。

       总之,保护继承时,基类对象可访问基类公有成员,派生类对象不能访问基类所有成员,而派生类的成员函数则可访问基类的公有成员和保护成员(但不能再往下继承)。

多重继承与虚继承:虚继承是为解决多重继承而出现的,是多重继承中特有的概念。例如,类D继承于类B和类C,而类B和类C又都继承于类A,即A类是B类和C类的基类,而B类和C类同时是D类的基类。为了节省内存空间 ,可以将B,C对A的继承定义为虚拟继承,则A就成了虚拟基类。用代码表示如下:

  class A ;

  class B:public virtual A;//虚拟继承

  class C:public virtual A;//虚拟继承

  class D:public B,public C;

  最后说明,在面向对象的程序设计中,继承和多重继承一般是指公共继承,很少用私有继承和保护继承

九、

    多态:允许将子类类型的指针赋值给父类类型的指针。多态性是通过虚函数实现的,是面向对象编程的核心概念。虚函数就是允许被其子类重新定义的成员函数,而子类重新定义父类虚函数的做法,叫做覆盖或重写。

    覆盖是指子类重新定义父类的虚函数的做法。重写的函数必须有一致的参数表和返回值(C++标准允许返回值不同的情况,但很少有编译器支持)

    重载是指编写一个与已有函数同名但参数表不同(个数或类型不同)的函数。即指允许存在多个同名函数, 但这些函数的参数表不同。重载的概念并不属于面向对象编程。它的实现是:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对编译器来说是这样的)。函数重载是静态联编的具体实现方式。调用重载函数时,编译根据调用时参数类型与个数在编译时实现静态联编,将调用地址与函数名进行绑定。所以说对于重载函数的调用,在编译期间就确定了,是静态的,也就是说它们的函数标识符与内存地址在编译期就绑定了(早绑定)。因此重载与多态无关

      在静态联编的方式下,同一成员函数(参数类型及个数相同,函数返回类型也相同)在基类与派生类中的不同版本是不会在运行时根据程序代码的指定进行自动绑定的,必须通过类的虚函数机制,才能实现基类和派生类中的成员函数不同版本的动态联编。动态联编是指函数标识符与内存地址在程序运行时动态绑定,而不在编译时静态绑定,所以又称晚绑定。虚函数是用关键字virtual来修饰基类中的public或protected的成员函数。当在派生类中进行重新定义后(函数覆盖),就可在此派生类中具有该成员函数的不同版本。在程序运行过程中,依据基类对象指针所指向的派生类对象,或通过基类引用对象所引用的派生类对象,才能确定哪个派生类中重新定义的成员函数被激活,从而实现动态联编。虚函数虽然只是在一般函数定义前加上virtual,但必须是类中成员函数;可把析构函数定义为虚函数,但不能把构造函数定义为虚函数,通常在释放基类中及其派生类中动态申请的存储空间时,也要把析构函数定义为虚函数,以便实现撤销对象时的多态性;虚函数在派生类重新定义时,参数个数和类型以及函数类型必须和基类的虚函数完全匹配,这一点与函数重载完全不同;虚函数派生下去仍是虚函数,且可省略virtual关键字

    当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态地调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(所调子类的虚函数的地址无法确定)。因此,这样的函数地址是在函数运行期间绑定的(晚绑定)。

    基类与派生类中的每个虚函数都在虚函数表中(vtable)占有一个表项,保存着一条跳转到它的入口地址的指令(实际上就是保存它的入口地址)。当一个包含虚函数的对象(注意,不是指针类型对象)被创建时,它在头部附加一个指针,指向vtable中相应的位置。调用虚函数的时候,不管是用什么指针调用的,它先根据 vtable找到入口地址再执行,从而实现了动态联编。而普通函数只有简单地跳转到一个固定的地址

十、

    只有类的成员函数才能访问类的私有成员,程序中的其它函数是无法访问私有成员的。非成员函数可以访问类中的公有成员,不能访问其私有成员。

    友元是一种定义在类外部的普通函数,但它需要在类中说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend友元不是成员函数,但它可以访问类中的私有成员。友元可以提高程序的运行效率。但是它破坏了类的封装性和隐藏性,使非成员函数也可以访问类的私有成员。友元可以是一个函数,称为友元函数;友元也可以是一个类,称为友元类。

十一、

     this指针:this指针是类中一个特殊指针,当类实例化(用类定义对象)时,this指针指向对象自己,而在类的声明时指向类本身。

十二、

    关于C++中class里面 static变量问题(即面向对象的程序设计中的static),与C中的static全局变量和局部变量含义不同(C是面向过程的程序设计)

  class B: 

  {

   public:

    static int a;

  };

  B b;

  int _tmain(int argc, _TCHAR* argv[])

  {

     b.a = 10;

     system("pause");

     return 0;

  }

   编译出现错误:

   Error error LNK2001: unresolved external symbol "public: static int B::a" 

    解决方法:必须初始化,初始化的时候要在类外;如下:添加int B::a = 0;也可在类中初始化,在类中写成static int a=0;      

    静态变量是属于类,而不是属于类对象的。也就是说不管你有多少个类对象,静态成员只有一个。 它的初始化,不能依赖于创建类对象时用于初始化对象的构造函数。

    静态数据成员也遵从 public/private/protected访问规则。类中的那个static int a; 只是声明,定义要放在外面int B::a = 0; // 此处可以初始化 。如果a是公有的,B::a就可以访问了(读取和修改)。 静态成员的提出是为了解决数据共享的问题。实现共享有许多方法,如:设置全局性的变量或对象是一种方法。但是,全局变量或对象是有局限性的。在类中,静态成员可以实现多个对象之间的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性。因此,静态成员是类的所有对象中共享的成员,而不是某个对象的成员

    使用静态数据成员可以节省内存,因为它是所有对象所公有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;

      同全局变量相比,使用静态数据成员有两个优势:静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;可以实现信息隐藏,静态数据成员可以是private成员,而全局变量不能;

  静态数据成员的使用方法和注意事项如下:

  1、静态数据成员在定义或说明时前面加关键字static。

  2、静态成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式如下:

    <数据类型><类名>::<静态数据成员名>=<值>

  这表明:

      (1) 初始化可在类外进行,而前面不加static,以免与一般静态变量或对象相混淆。当然也可在类中初始化。

  (2) 初始化时不加该成员的访问权限控制符private,public等。

  (3) 初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员。

  3、静态数据成员是静态存储的,它是静态生存期,必须对它进行初始化

  4、引用静态数据成员时,采用如下格式:<类名>::<静态成员名>

      如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员。

 

     与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分。普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this 是缺省的。如函数fn()实际上是this->fn()。但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数和静态数据成员。而非静态成员函数(普通函数)可以访问静态数据成员和调用其余的静态成员函数。

关于静态成员函数,可以总结为以下几点:

1、出现在类体外的函数定义不能指定关键字static;

2、静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;

3、非静态成员函数可以任意地访问静态成员函数和静态数据成员;

4、静态成员函数不能访问非静态成员函数和非静态数据成员;

5、由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;

6、调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,

     也可以直接使用如下格式:<类名>::<静态成员函数名>(<参数表>)调用类的静态成员函数。

转载于:https://www.cnblogs.com/King-Gentleman/p/4822425.html

更多相关:

  • ::是域作用符,是各种域性质的实体(比如类(不是对象)、名字空间等)调用其成员专用的。 (如果有个局部变量与全局变量同名(假设都是int a;),默认调用的 a 是局部变量,如果要访问全局变量a,就要这么写“::a”。使用域作用符来加以区别;前面没写具体的域名,就是指默认域).是成员作用符,是对象专用的。比如 struct A {...

  •   static关键字 1.修饰成员变量 在我们平时的使用当中,static最常用的功能就是修饰类的属性和方法,让他们成为类的成员属性和方法,我们通常将用static修饰的成员称为类成员或者静态成员,这句话挺起来都点奇怪,其实这是相对于对象的属性和方法来说的。请看下面的例子:(未避免程序太过臃肿,暂时不管访问控制) public...

  • 1、今天解决的进度 成员进度陈家权回复界面设计,由于成员变动加上和其他成员距离较远,服务器404赖晓连改进Alpha版本页面没能及时更新的问题雷晶获取提问问题时间更新到数据库林巧娜今天的任务是夜间模式功能块,没有完成,查找了很多教程,一一使用了,但是在手机端试运行的时候,一点击开关就会出现app黑屏卡死的状态,是recreate()方...

  • Python Class 对象或类型通过内置成员 __dict__ 来存储成员信息。 我们还可以通过重载 __getattr__ 和 __setattr__ 来拦截对成员的访问,需要注意的是 __getattr__ 只有在访问不存在的成员时才会被调用。 转载于:https://www.cnblogs.com/Huayuan/arc...

  • 草色新雨中, 松声晚窗里。之前我们学习 Power Query 都是用鼠标就完成了很多复杂的操作。虽然 PowerQuery 已经将大部分常用功能内置成到功能区。基本能完成我们大部分的报表自动化功能。但是总有些复杂的或者个性化的问题是开发团队没有预先想到的,这时我们就需要学习 M 语言。一、M 语言在哪里?M语言的函数公式有三个地...

  • 前言从2020年3月份开始,计划写一系列文档--《小白从零开始学编程》,记录自己从0开始学习的一些东西。第一个系列:python,计划从安装、环境搭建、基本语法、到利用Django和Flask两个当前最热的web框架完成一个小的项目第二个系列:可能会选择Go语言,也可能会选择Vue.js。具体情况待定,拭目以待吧。。。基本概念表达式表...

  • 1.1函数1.1.1什么是函数函数就是程序实现模块化的基本单元,一般实现某一功能的集合。函数名:就相当于是程序代码集合的名称参数:就是函数运算时需要参与运算的值被称作为参数函数体:程序的某个功能,进行一系列的逻辑运算return 返回值:函数的返回值能表示函数的运行结果或运行状态。1.1.2函数的作用函数是组织好的,可重复使用的,用来...

  • 原标题:基于Python建立深度神经网络!你学会了嘛?图1 神经网络构造的例子(符号说明:上标[l]表示与第l层;上标(i)表示第i个例子;下标i表示矢量第i项)单层神经网络图2 单层神经网络示例神经元模型是先计算一个线性函数(z=Wx+b),接着再计算一个激活函数。一般来说,神经元模型的输出值是a=g(Wx+b),其中g是激活函数(...

  • 在学习MySQL的时候你会发现,它有非常多的函数,在学习的时候没有侧重。小编刚开始学习的时候也会有这个感觉。不过,经过一段时间的学习之后,小编发现尽管函数有很多,但是常用的却只有那几个。今天小编就把常用的函数汇总一下,为大家能够能好的学习MySQL中的函数。MySQL常使用的函数大概有四类。时间函数、数学函数、字符函数、控制函数。让我...

  • 点云PCL免费知识星球,点云论文速读。文章:DSP-SLAM: Object Oriented SLAM with Deep Shape Priors作者:Jingwen Wang Martin Runz Lourdes Agapito编译:点云PCL代码:https://github.com/JingwenWang95/DSP-S...

  • RAM缓存 新RAM缓存算法(CLFUS) 新的RAM缓存使用的创意来自许多缓存替换策略和算法,包括LRU,LFU,CLOCK,GDFS及2Q,它被命名为时钟周期内最小频繁使用大小算法CLFUS(Clocked Least Frequently Used by Size)。它避开了任何专利算法,具有如下特性: 均衡最近性(Rec...

  • MP4 |视频:AVC,1280×720 30 fps |音频:AAC,48 KHz,2 Ch |时长:2h 12m 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小解压后:560M C4D是一个有抱负的运动图形艺术家和设计师的重要工具。借助C4D,您可以使用3D对象、动态效果和动画来增强运动图形、模型和可视化效果。本课...

  • 文章目录先说问题:再说解决尝试1:尝试2(该尝试建议先在自己环境搭配对应业务测试通过后再现场尝试): 感谢 学无止境996同学的陪伴和vigourtyy美丽女友的支持,直到这个解决问题的深夜 先说问题: ceph 12.2.1生产环境:3副本 tier + 3副本data 机房在拥有业务的情况下重启集群交换机,产生如下场景...

  • 这周主要学习了java中的类和对象的知识点,发现和C++中的类和对象极为相似,对于类和对象的概念理解起来也简单。同时在自学的过程中也把类的知识重新复习巩固了一下(如类的三大特征:继承,封装和多态,构造,成员对象的访问权限,构造,无参有参函数的调用等),同时也了解到一些新的概念,比如类对象创建和引用占据堆内存和栈内存,输出对象时默认调...