当前位置: 首页 > news >正文

重庆知名网站建设免费建设一个商业网站费用

重庆知名网站建设免费,建设一个商业网站费用,wordpress移动端标签,大数据培训哪家好一.继承 1.理解继承 C中的继承是类与类之间的关系#xff0c;是一个很简单很直观的概念#xff0c;与现实世界中的继承类似#xff0c;例如儿子继承父亲的财产。 继承可以理解为一个类从另一个类获取成员变量和成员函数的过程。例如类 B 继承于类 A#xff0c;那么 B 就…一.继承 1.理解继承 C中的继承是类与类之间的关系是一个很简单很直观的概念与现实世界中的继承类似例如儿子继承父亲的财产。 继承可以理解为一个类从另一个类获取成员变量和成员函数的过程。例如类 B 继承于类 A那么 B 就拥有 A 的成员变量和成员函数。 在C中派生和继承是一个概念只是站的角度不同。继承是儿子接收父亲的产业派生是父亲把产业传承给儿子。 被继承的类称为父类或基类继承的类称为子类或派生类。“子类”和“父类”通常放在一起称呼“基类”和“派生类”通常放在一起称呼。 派生类除了拥有基类的成员还可以定义自己的新成员以增强类的功能。 以下是两种典型的使用继承的场景 当你创建的新类与现有的类相似只是多出若干成员变量或成员函数时可以使用继承这样不但会减少代码量而且新类会拥有基类的所有功能。 当你需要创建多个类它们拥有很多相似的成员变量或成员函数时也可以使用继承。可以将这些类的共同成员提取出来定义为基类然后从基类继承既可以节省代码也方便后续修改成员。 继承的一般语法为 class 派生类名:继承方式 基类名{派生类新增加的成员 };继承方式包括 public公有的、private私有的和 protected受保护的此项是可选的如果不写那么默认为 private。 现在我们知道public、protected、private 三个关键字除了可以修饰类的成员还可以指定继承方式。 2.继承方式 不同的继承方式会影响基类成员在派生类中的访问权限。 1) public继承方式 基类中所有 public 成员在派生类中为 public 属性基类中所有 protected 成员在派生类中为 protected 属性基类中所有 private 成员在派生类中不能使用。 2) protected继承方式 基类中的所有 public 成员在派生类中为 protected 属性基类中的所有 protected 成员在派生类中为 protected 属性基类中的所有 private 成员在派生类中不能使用。 3) private继承方式 基类中的所有 public 成员在派生类中均为 private 属性基类中的所有 protected 成员在派生类中均为 private 属性基类中的所有 private 成员在派生类中不能使用。 注意我们这里说的是基类的 private 成员不能在派生类中使用并没有说基类的 private 成员不能被继承。实际上基类的 private 成员是能够被继承的并且成员变量会占用派生类对象的内存它只是在派生类中不可见导致无法使用罢了。private 成员的这种特性能够很好的对派生类隐藏基类的实现以体现面向对象的封装性。 在派生类中访问基类 private 成员的唯一方法就是借助基类的非 private 成员函数如果基类没有非 private 成员函数那么该成员在派生类中将无法访问。 3.改变访问权限 使用 using 关键字可以改变基类成员在派生类中的访问权限例如将 public 改为 private、将 protected 改为 public。 注意using 只能改变基类中 public 和 protected 成员的访问权限不能改变 private 成员的访问权限因为基类中 private 成员在派生类中是不可见的根本不能使用所以基类中的 private 成员在派生类中无论如何都不能访问。 //基类People class People { public:void show(); protected:char *m_name;int m_age; }; void People::show() {cout m_name 的年龄是 m_age endl; }//派生类Student class Student : public People { public:void learning(); public:using People::m_name; //将protected改为publicusing People::m_age; //将protected改为publicfloat m_score; private:using People::show; //将public改为private };我们可以看到在派生类中对应的权限下进行using的基类成员再声明即可改变类成员在派生类中的访问权限。 二.同名遮蔽问题 1.遮蔽 如果派生类中的成员包括成员变量和成员函数和基类中的成员重名那么就会遮蔽从基类继承过来的成员。所谓遮蔽就是在派生类中使用该成员包括在定义派生类时使用也包括通过派生类对象访问该成员时实际上使用的是派生类新增的成员而不是从基类继承来的。 #includeiostream using namespace std;class Base { public:int m_a;void func() {cout Base的func调用 endl;}Base() {m_a 100;} };class Son :public Base { public:int m_a; //同名成员属性void func() { //同名成员方法cout Son的func调用 endl;}Son() {m_a 200;} };//测试同名属性 void test01() {Son s;cout Son下的m_a为 s.m_a endl;cout Base下的m_a为 s.Base::m_a endl; }//测试同名方法 void test02() {Son p;p.func();p.Base::func(); } int main() {test01();test02();return 0; }还需要补充的是即使你在基类中使用函数重载而派生类只有同名函数而没有对应的重载想要在派生类中调用即类的某个重载函数也是不可能的因为派生类中只要出现同名就会遮蔽即类中所有的同名函数无论其是否构成重载。 总结: 1.子类对象可以直接访问到子类中同名成员2.子类对象加作用域可以访问到父类同名成员3.当子类与父类拥有同名的成员函数子类会隐藏父类中同名成员函数加作用域可以访问到父类中同名函数 2.同名静态成员处理 首先复习一下静态成员知识点 静态成员变量 所有对象共享同一份数据在编译阶段分配内存类内声明类外初始化 静态成员函数 所有对象共享同一个函数静态成员函数只能访问静态成员变量 上面我们知道了一般成员的同名遮蔽问题和怎么处理那么静态成员的处理是不是一样的呢 其实静态成员和非静态成员出现同名处理方式一致 访问子类同名成员 直接访问即可访问父类同名成员 需要加作用域 三.继承知识点 1.继承中的对象模型 第二部分就说过有继承关系时派生类的内存模型可以看成是基类非静态成员变量和新增成员变量的总和而所有成员函数仍然存储在另外一个区域——代码区由所有对象共享。 那么存在成员变量遮蔽时的内存分布模型是怎么样的呢通过开发人员工具我们知道假设A类有属性m_aB有m_b且遮蔽m_a那么总共应该有m_a、m_b、A::m_a三份数据。 #includeiostream using namespace std;class Base { public:int m1;static int m0; //静态变量 private:int m2; };class Son :public Base { public:int m1;//同名遮蔽int m3;//新增变量 };void test01() {cout 基类的内存模型大小为 sizeof(Base) endl;cout 派生类的内存大小为 sizeof(Son) endl; }int main() {test01();return 0; }运行结果为 基类的内存模型大小为8 派生类的内存大小为16 总结一下计算类的大小时首先排除静态变量然后判断是否有继承继承又是否有同名遮蔽问题。 2.构造和析构顺序 #includeiostream using namespace std;class Base { public:Base() {cout Base的构造函数 endl;}~Base() {cout Base的析构函数 endl;} };class Son :public Base { public:Son() {cout Son的构造函数 endl;}~Son() {cout Son的析构函数 endl;} };void test01() {Son s; }int main() {test01();return 0; }运行结果 Base的构造函数 Son的构造函数 Son的析构函数 Base的析构函数 可以很明显的看到当存在继承关系时我们虽然自定义了一个派生类对象但是它也调用了基类的构造函数与析构函数构造函数的顺序是先调用基类再调用派生类而析构函数则与此相反。 注意还记得我们之前的封闭类吗注意区分二者调用构造与析构的顺序。 3.构造与析构 前面我们说基类的成员函数可以被继承可以通过派生类的对象访问但这仅仅指的是普通的成员函数类的构造函数不能被继承。构造函数不能被继承是有道理的因为即使继承了它的名字和派生类的名字也不一样不能成为派生类的构造函数当然更不能成为普通的成员函数。 在设计派生类时对继承过来的成员变量的初始化工作也要由派生类的构造函数完成但是大部分基类都有 private 属性的成员变量它们在派生类中无法访问更不能使用派生类的构造函数来初始化。 这种矛盾在C继承中是普遍存在的解决这个问题的思路是在派生类的构造函数中调用基类的构造函数。 事实上通过派生类创建对象时必须要调用基类的构造函数这是语法规定。换句话说定义派生类构造函数时最好指明基类构造函数如果不指明就调用基类的默认构造函数不带参数的构造函数如果没有默认构造函数那么编译失败。 和构造函数类似析构函数也不能被继承。与构造函数不同的是在派生类的析构函数中不用显式地调用基类的析构函数因为每个类只有一个析构函数编译器知道如何选择无需程序员干涉。 另外析构函数的执行顺序和构造函数的执行顺序也刚好相反 创建派生类对象时构造函数的执行顺序和继承顺序相同即先执行基类构造函数再执行派生类构造函数。而销毁派生类对象时析构函数的执行顺序和继承顺序相反即先执行派生类析构函数再执行基类析构函数。 四.多继承 1.多继承 在前面的例子中派生类都只有一个基类称为单继承。除此之外C也支持多继承即一个派生类可以有两个或多个基类。 多继承的语法也很简单将多个基类用逗号隔开即可。例如已声明了类A、类B和类C那么可以这样来声明派生类D class D: public A, private B, protected C{//类D新增加的成员 }D 是多继承形式的派生类它以公有的方式继承 A 类以私有的方式继承 B 类以保护的方式继承 C 类。D 根据不同的继承方式获取 A、B、C 中的成员确定它们在派生类中的访问权限。 二义性问题 ​ 当两个或多个基类中有同名的成员时如果直接访问该成员就会产生命名冲突编译器不知道使用哪个基类的成员。这个时候需要在成员名字前面加上类名和域解析符::以显式地指明到底使用哪个类的成员消除二义性。 2.多继承的对象内存模型 、B 是基类C 是派生类假设 obj_c 的起始地址是 0X1000那么 obj_c 的内存分布如下图所示 基类对象的排列顺序和继承时声明的顺序相同。 五.虚继承 1.菱形继承 多继承时很容易产生命名冲突即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字命名冲突依然有可能发生比如典型的是菱形继承如下图所示 类 A 派生出类 B 和类 C类 D 继承自类 B 和类 C这个时候类 A 中的成员变量和成员函数继承到类 D 中变成了两份一份来自 A–B–D 这条路径另一份来自 A–C–D 这条路径。 在一个派生类中保留间接基类的多份同名成员虽然可以在不同的成员变量中分别存放不同的数据但大多数情况下这是多余的因为保留多份成员变量不仅占用较多的存储空间还容易产生命名冲突。假如类 A 有一个成员变量 a那么在类 D 中直接访问 a 就会产生歧义编译器不知道它究竟来自 A --B–D 这条路径还是来自 A–C–D 这条路径。 菱形继承也叫钻石继承也就是典型的钻石问题。 2.虚继承 为了解决多继承时的命名冲突和冗余数据问题C 提出了虚继承使得在派生类中只保留一份间接基类的成员。 在继承方式前面加上 virtual 关键字就是虚继承 //间接基类A class A{ protected:int m_a; }; //直接基类B class B: virtual public A{ //虚继承 protected:int m_b; }; //直接基类C class C: virtual public A{ //虚继承 protected:int m_c; }; //派生类D class D: public B, public C{ public:void seta(int a){ m_a a; } //正确void setb(int b){ m_b b; } //正确void setc(int c){ m_c c; } //正确void setd(int d){ m_d d; } //正确 private:int m_d; }; int main(){D d;return 0; }这里B和C继承A的方式就叫虚继承而A类称为虚基类。 这段代码使用虚继承重新实现了上图所示的菱形继承这样在派生类 D 中就只保留了一份成员变量 m_a直接访问就不会再有歧义了。 3.虚继承的构造函数 ​ 在虚继承中虚基类是由最终的派生类初始化的换句话说最终派生类的构造函数必须要调用虚基类的构造函数。对最终的派生类来说虚基类是间接基类而不是直接基类。这跟普通继承不同在普通继承中派生类构造函数中只能调用直接基类的构造函数不能调用间接基类的。 ​ 另外需要关注的是构造函数的执行顺序。虚继承时构造函数的执行顺序与普通继承时不同在最终派生类的构造函数调用列表中不管各个构造函数出现的顺序如何编译器总是先调用虚基类的构造函数再按照出现的顺序调用其他的构造函数而对于普通继承就是按照构造函数出现的顺序依次调用的。 4.虚继承的内存模型 对于普通继承基类子对象始终位于派生类对象的前面也即基类成员变量始终在派生类成员变量的前面而且不管继承层次有多深它相对于派生类对象顶部的偏移量是固定的。 前面我们说过编译器在知道对象首地址的情况下通过计算偏移来存取成员变量。对于普通继承基类成员变量的偏移是固定的不会随着继承层级的增加而改变存取起来非常方便。 而对于虚继承恰恰和普通继承相反大部分编译器会把基类成员变量放在派生类成员变量的后面这样随着继承层级的增加基类成员变量的偏移就会改变就得通过其他方案来计算偏移量。 六.向上转型 在 C/C中经常会发生数据类型的转换例如将 int 类型的数据赋值给 float 类型的变量时编译器会先把 int 类型的数据转换为 float 类型再赋值反过来float 类型的数据在经过类型转换后也可以赋值给 int 类型的变量。 类其实也是一种数据类型也可以发生数据类型转换不过这种转换只有在基类和派生类之间才有意义并且只能将派生类赋值给基类包括将派生类对象赋值给基类对象、将派生类指针赋值给基类指针、将派生类引用赋值给基类引用这在 C 中称为向上转型。相应地将基类赋值给派生类称为向下转型。**** 向上转型非常安全可以由编译器自动完成向下转型有风险需要程序员手动干预。 赋值的本质是将现有的数据写入已分配好的内存中对象的内存只包含了成员变量所以对象之间的赋值是成员变量的赋值成员函数不存在赋值问题。运行结果也有力地证明了这一点虽然有ab;这样的赋值过程但是 a.show() 始终调用的都是 A 类的 display() 函数。换句话说对象之间的赋值不会影响成员函数也不会影响 this 指针。 派生类对象赋值给基类对象时会舍弃派生类新增的成员也就是“大材小用”以发现即使将派生类对象赋值给基类对象基类对象也不会包含派生类的成员所以依然不同通过基类对象来访问派生类的成员。 这种转换关系是不可逆的只能用派生类对象给基类对象赋值而不能用基类对象给派生类对象赋值。理由很简单基类不包含派生类的成员变量无法对派生类的成员变量赋值。同理同一基类的不同派生类对象之间也不能赋值。
http://www.zqtcl.cn/news/720237/

相关文章:

  • 52做网站南京市住房城乡建设门户网站
  • 网站开发精品课程贵阳市白云区官方网站
  • seo整站优化服务会计培训班一般收费多少
  • 批量网站访问检测怎么做好手机网站开发
  • 深圳网站建设公司哪家比较好shortcodes wordpress
  • 网站内链越多越好嘛可以做3d电影网站
  • 企业网站需求文档微商引流客源最快的方法
  • 交互式网站备案业务网站在线生成
  • 自建网站百度个人网站如何在百度上做推广
  • 如何安装wordpress模板竞价网站做seo
  • 做论坛网站如何赚钱电子商务营销推广
  • 想要自己做一个网站怎么做济宁百度网站建设
  • 海会网络建设网站wordpress刷不出图片
  • 一个人做商城网站网站推广的几个阶段
  • 做国学类网站合法吗html5教程pdf下载
  • 云南省文化馆网站建设二级域名分发平台
  • 网站版面布局结构图网站收录批量查询
  • 网站开发手机模拟器常州到丹阳
  • 淮南医院网站建设班级网站开发报告
  • 东莞营销网站建设哪家好微信api接口
  • 凡科建站怎么导出网页wordpress视频采集插件
  • 个人介绍网站源码云主机上传网站
  • app推广平台网站系统登录入口
  • 做公司宣传册的网站成crm网
  • 新乡公司做网站军事新闻内容摘抄
  • 讯美智能网站建设泰安网络科技有限公司电话
  • 新泰建设局网站北京公司排名seo
  • 新网站上线wordpress用户登陆
  • 景安网站备案表格首页风格
  • 做网站卖菜刀需要什么手续互联网营销顾问