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

排名好的网站关键词优化企业二级域名怎么设置

排名好的网站关键词优化企业,二级域名怎么设置,做网站通常到哪找图片,建设企业网站新闻开发的意义目录 1、继承的概念与意义 2、继承的使用 2.1继承的定义及语法 2.2基类与派生类间的转换 2.3继承中的作用域 2.4派生类的默认成员函数 1构造函数 2拷贝构造函数 3赋值重载函数 4析构函数 5总结 3、继承与友元 4、继承与静态变…目录 1、继承的概念与意义 2、继承的使用 2.1继承的定义及语法 2.2基类与派生类间的转换 2.3继承中的作用域 2.4派生类的默认成员函数 1构造函数 2拷贝构造函数 3赋值重载函数 4析构函数 5总结 3、继承与友元 4、继承与静态变量 5、菱形继承及菱形虚拟继承 6、继承与组合 1、继承的概念与意义 什么是继承 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段它允许我们在保持原有类特性的基础上进行扩展增加方法(成员函数)和属性(成员变量)这样产生新的类称派生类。 继承呈现了面向对象程序设计的层次结构体现了由简单到复杂的认知过程。以前我们接触的函数层次的复用继承是类设计层次的复用。 通过继承联系在一起的类构成了一种层次关系在这种关系中有一个基类base class其他类则是直接或间接地从基类继承过来的这些继承来的类可以称为派生类drived class。基类通常有着层次关系中所有类共同拥有维护的成员而每个派生类也有着自己各自特定的成员。 一个简单的例子一个学习管理系统那么成员必定有学生老师等等这些是身份归根到底是个人基类包含着名字、年龄、地址等基础信息。这些需要共同维护的就是基类的成员。 //共同维护的成员部分-基类 class Person { public:// 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证 void identity(){cout void identity() _name endl;} protected:string _name qsy; // 姓名 string _address; // 地址 string _tel; // 电话 int _age 18; // 年龄 };class Student : public Person { public:// 学习 void study(){// ...} protected:int _stuid; // 学号 }; class Teacher : public Person { public:// 授课 void teaching(){//...} protected:string title; // 职称 }; int main() {Student s;Teacher t;s.identity();t.identity();return 0; } 可以看到派生类可以访问基类成员 如果没有继承这种结构关系的话 Student和Teacher 都有姓名/地址/ 电话/年龄等成员变量都有identity身份认证的成员函数设计到两个类里面就是冗余的。更好地体现了继承是类设计层次的复用。 2、继承的使用 2.1继承的定义及语法 这就是继承的语法格式 继承方式与访问限定符号一样有着三种不同的继承方式与不同的类成员组合会是不同的情况 总结一下规律 1基类 private 成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它。 将年龄变为私有验证一下是否继承到了派生类对象 可以看到继承下来了但是不可以访问 2如果基类成员不想在类外直接被访问但需要在派生类中能访问就定义为 protected。可以看出保护成员限定符是因继承才出现的。 如果想要访问 private 成员可以在基类中成员函数访问这样派生类可以间接访问到 private成员 3基类的私有成员在派生类都是不可见。基类的其他成员在派生类的访问方式 Min(成员在基类的访问限定符继承方式)public   protected  private。 Tipclass默认继承方式是 privatestruct默认继承方式是public。最好显示写出继承方式 4在实际运用中⼀般使用都是 public 继承几乎很少使用 protetced/private 继承也不提倡使用protetced/private继承因为protetced/private继承下来的成员都只能在派生类的类里面使用实 际中扩展维护性不强。 2.2基类与派生类间的转换 基类与派生类之间是否有着类型的转换呢 答案是可以的 public继承中有一个 is-a 概念每个派生类都是一个特殊的基类对象 • public继承的派生类对象 可以赋值给 基类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割。寓意把派生类中基类那部分切出来基类指针或引用指向的是派生类中切出来的基类那部分。 • 基类对象不能赋值给派生类对象 • 基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的。这里基类如果是多态类型可以使用RTTI(Run-Time Type  Information)的dynamic_cast 来进行识别后进行安全转换。 2.3继承中的作用域 继承体现中也有各自的作用域规则并且引出来一个隐藏概念隐藏影响的只是编译器查找规则 1. 在继承体系中基类和派生类都有独立的作用域。 2. 派生类和基类中有同名成员派生类成员将屏蔽基类对同名成员的直接访问这种情况叫隐藏。 在派生类成员函数中可以使用 基类::基类成员显示访问 3. 需要注意的是如果是成员函数的隐藏只需要函数名相同就构成隐藏。区分重载 4. 注意在实际中在继承体系里面最好不要定义同名的成员。 // Student的_num 和 Person的_num 构成隐藏关系可以看出这样代码虽然能跑但是⾮常容易混淆 class Person { protected:string _name 小徐; // 姓名 int _num 111; // ⾝份证号 }; class Student : public Person { public:void Print(){cout 姓名: _name endl;cout 身份证号: Person::_num endl;cout 学号: _num endl;} protected:int _num 999; // 学号 }; int main() {Student s1;s1.Print();return 0; };访问的是哪个 _num 呢 可以看到派生类成员隐藏了基类的同名成员直接访问了派生类的 _num  同理函数也有隐藏的现象 A和B类中的 fun 两个函数构成什么关系呢根据前面的知识可以知道继承体系中函数名相同就构成隐藏关系 2.4派生类的默认成员函数 6个默认成员函数默认的意思就是指我们不写编译器会自动生成⼀个那么在派生类中这 几个成员函数是如何生成的呢 四个常见默认成员函数 1构造函数 派生类的构造函数必须调用基类的构造函数初始化基类的那⼀部分成员。 class Person { public:Person(const char* namexxc) //全缺省函数默认构造:_name(name){cout Person() endl;} protected:string _name;//姓名 };class Student :public Person { public://不显示实现默认构造编译器生成的// 1. 内置类型-不确定// 2. 自定义类型-调用自定义类型的显示写的默认构造// 3. 基类成员看作一个整体要求调用基类的默认构造 protected:int _num;//学号string _addrss;//地址 };int main() {Student s1;return 0; } 如果基类没有默认的构造函数则必须在派生类构造函数的初始化列表阶段显示调用。 写一个 Student的构造函数 还是报错前面提到 需要把基类成员当成一个对象调用基类的构造函数 如何实现一个不能被继承的类呢 方法1基类的构造函数私有派生类的构成必须调用基类的构造函数但是基类的构成函数私有化以后派生类看不见就不能调用了那么派生类就无法实例化出对象。 方法2C11新增了⼀个final关键字final 修改基类派生类就不能继承了。 2拷贝构造函数 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。 可以看到没有资源申请的时候 Student 并不需要自己显示实现拷贝构造因为编译器默认拷贝构造会调用基类的拷贝构造 那么怎么自己实现拷贝构造呢Tip基类对象是最先声明内存顺序的初始化列表中第一个初始化 Person(const Person p): _name(p._name) {cout Person(const Person p) endl; }Student(const Student s):Person(s),_num(s._num),_addrss(s._addrss) {//深拷贝 } Persons 这个 s 是派生类对象的引用为什么可以传给基类呢 涉及基类与派生类间的转换概念——切片  如果显示写了拷贝构造但是不显示调用基类的拷贝构造的会编译器会自动调用默认构造而非调用基类的拷贝构造 补充一下缺省值构成默认构造运行一下发现调用的就是默认构造而非拷贝构造 3赋值重载函数 派生类的operator必须要调用基类的operator完成基类的复制。 赋值重载与拷贝构造类似一般编译器默认生成的就已经够用了如果有资源申请的话才需要显示实现 Student operator(const Student s) {if (this ! s){operator(s);//派生类切片基类成员_num s._num;_addrss s._addrss;}return *this; } 栈溢出无限递归调用我们不是想要调用基类的赋值函数吗为什么调用了派生类的呢 需要注意的是派生类的 operator 隐藏了基类的operator 所以显示调用基类的operator 需要指定基类作用域 Student operator(const Student s) {if (this ! s){//基类和派生类的赋值构成了隐藏关系 需要指定作用域Person::operator(s);//派生类切片基类成员_num s._num;_addrss s._addrss;}return *this; } 4析构函数 析构函数可以显示调用那么可以在派生类显示调用基类的析构函数来清理基类成员 可是为什么调不动呢这里派生类和基类的析构函数构成了隐藏关系 因为多态中⼀些场景析构函数需要构成重写重写的条件之一是函数名相同那么编译器会对析构函数名进行特殊处理处理成destructor()所以基类析构函数不加 virtual的情况下派生类析构函数和基类析构函数构成隐藏关系。 想要调用就标明作用域 Person::~Person() 但是像上述这样写会有一个问题基类的析构会调用两次 其实派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。所以我们不必在派生类的析构函数中进行调用基类的析构函数不然就会重复释放同一块空间导致报错 可以怎么理解派生类析构自动调用基类的析构呢 先子后父保证析构顺序显示调用不一定保证先子后父的析构顺序 5总结 派生类和基类的层次关系逻辑基础还是类和对象 派生类的默认成员函数的注意事项 1派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数则必须在派生类构造函数的初始化列表阶段显示调用。 2派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。 3派生类的operator必须要调用基类的operator完成基类的复制。 4派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员(不需要显示和调用基类析构。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。 5派生类对象初始化先调用基类构造再调派生类构造。派生类对象析构清理先调用派生类析构再调基类的析构。 6因为后续一些场景析构函数需要构成重写重写的条件之一是函数名相同那么编译器会对析构函数名进行特殊处理处理成destrutor()所以父类析构函数不加virtual的情况下子类析构函数和父类析构函数构成隐藏关系 3、继承与友元 友元关系不能继承也就是说基类友元不能访问派生类私有和保护成员。比如爸爸的朋友可以说是你的朋友吗 class Student;//前置声明 class Person { public:friend void Display(const Person p, const Student s);//需要前置声明否则报错招不到 Student protected:string _name; // 姓名 }; class Student : public Person { protected:int _stuNum; // 学号 }; void Display(const Person p, const Student s) {cout p._name endl; } int main() {Person p;return 0; } 如果访问派生类的私有和保护成员呢 可以看见是不可访问的 在派生类同样设置一个友元就可以解决这个问题了。 4、继承与静态变量 基类定义了 static 静态成员则整个继承体系里面只有⼀个这样的成员。无论派生出多少个派生类都只有⼀个static 成员实例。 验证一下 class A { public: static int _a;int _aa; }; class B :public A { public:int _b; }; // static int _a 1;报错int A::_a 1;//注意定义的方式 int main() {A a;B b1;B b2;//这⾥的运行结果可以看到非静态成员_aa的地址是不⼀样的// 说明派生类继承下来了⽗类派生类对象各有⼀份 cout a._aa endl;cout b1._aa endl;cout endl;// 这⾥的运行结果可以看到静态成员 _a 的地址是⼀样的 //说明派生类和基类共用同⼀份静态成员 cout a._a endl;cout b1._a endl;cout b2._a endl;cout endl;//公有情况下 基类派生类都可以访问静态成员变量cout a._a endl;cout b1._a endl;cout b2._a endl;return 0; } 也就说明他们共用一个_a变量所以无论派生出多少个子类都只有一个static成员实例 这个特性可以带来一种思路统计实例化类的数量个数只需在构造函数中加入一个增加该静态变量的语句即可 class Person { public:Person() { _count; }//子类的构造会调用父类构造 protected:string _name; // 姓名 public:static int _count; // 统计人的个数。 }; int Person::_count 0;class Student : public Person { protected:int _stuNum; // 学号 }; int main() {Student s1;Student s2;Student s3;cout 人数 : Person::_count endl;Student::_count 0;cout 人数 : Person::_count endl;return 0; }这样我们就可以知道该继承体系中实例化了多少个类了 5、菱形继承及菱形虚拟继承 首先声明一下由于C的历史缘故其一致行走在语言发展的前端一直在尝试新的内容。在发展过程中有些内容加入到C的时候还没有发现其弊端。而后来发现的时候为了向上兼容只能打补丁所以不开避免的不会有一些弊端会有复杂的语法和复杂的特性。总要有先驱者走前前面而C就是 单继承⼀个派生类只有⼀个直接基类时称这种继承关系为单继承 多继承⼀个派生类有两个或以上直接基类时称这种继承关系为多继承多继承对象在内存中的模型是先继承的基类在前面后面继承的基类在后面派生类成员在放到最后面。 菱形继承菱形继承是多继承的⼀种特殊情况。 菱形继承的问题从上面的对象成员模型构造可以看出菱形继承有数据冗余和二义性的问题在Assistant的对象中Person成员会有两份。 class Person { public:string _name; // 姓名 }; class Student : public Person { protected:int _num; //学号 }; class Teacher : public Person { protected:int _id; // 职⼯编号 }; class Assistant : public Student, public Teacher { protected:string _majorCourse; // 主修课程 }; int main() {// 编译报错error C2385: 对“_name”的访问不明确 二义性Assistant a;a._name peter;// 需要显⽰指定访问哪个基类的成员可以解决⼆义性问题但是数据冗余问题⽆法解决 a.Student::_name xxx;a.Teacher::_name yyy;return 0; }那该如何解决数据冗余的问题呢可以借用虚拟继承 虚拟继承virtual可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系在Student和Teacher的继承Person时使用虚拟继承即可解决问题。 这是什么原理呢测试一下 菱形继承不虚拟继承的情况 #includeiostream #includestringusing namespace std;class A { public:int _a; };class B : public A //class B : virtual public A { public:int _b; };class C : public A //class C : virtual public A { public:int _c; }; class D : public B, public C { public:int _d; }; int main() {D d;d.B::_a 1;d.C::_a 2;d._b 3;d._c 4;d._d 5;return 0; }调试一下 通过这个逐语句调试的内存变化我们可以确定大致的内存情况 不使用虚拟继承就是这样的内存情况也好理解为什么同名变量的两份是如何储存的了。 接下来我们来看虚拟继承下的菱形继承是怎么个情况 内存分布 a储存在最下面而B,C部分的原有储存_a的位置现在是什么呢 其实是个指针那我们来看看指针指向的空间储存着什么吧 怎么对应位置是00 00 00 00为什么是零往下看看 分别储存着16进制数字14 0c转换为10进制数字20 12然后对应B,C原本的指针位置006FFB6C加上这个值偏移量都会指向到A _a的空间这个00 00 00 00到多态的部分再来进行讲解知道原地址加上下面的值就是A _a的空间就可以了 这里是通过了B和C的两个指针指向的一张表。这两个指针叫虚基表指针这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A。 即原本B,C中_a的位置储存这一个指针指针指向的位置有一个偏移量原位置的地址加上偏移量就会指向A的空间 那这样进行拷贝切片的时候是怎样的呢一样是把D中B对象的部分切片然后通过虚基表的方式来找到_a。但这样也带来了一些代价PS内存中的储存顺序就是声明的顺序先继承谁谁就在前面 多继承指针偏移问题切片 p1和p2指向哪里呢 内存分布中先继承的放前面 因为切片的概念p2指向 base2开始但是只能看见 base2 那一部分 6、继承与组合 public继承是一种is-a谁是什么的关系。也就是说每个派生类对象都是一个基类对象。组合是一种has-a谁有什么的关系。假设B组合了A每个B对象中都有一个A对象也就是把A作为B的成员变量 继承允许你根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称为白箱复用(white-box reuse 能看见不安全耦合度高)。术语 “白箱”是相对可视性而言在继承方式中基类的内部细节对子类可见 。继承一定程度破坏了基类的封装基类的改变对派生类有很大的影响。派生类和基类间的依赖关系很强耦合度高。 对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse 不能能看见安全耦合度低)因为对象的内部细节是不可见的。对象只以“黑箱”的形式出现。组合类之间没有很强的依赖关系耦合度低。优先使用对象组合有助于你保持每个类被封装。 有关继承的经典面试题1C有多继承为什么java等语言没有 历史原因C是先驱者人的直觉认为多继承很合理我感觉正常人都会想到多继承并且c中的多继承处理起来十分复杂访问基类变量的过程就会很复杂java等后来发展的语言见到c中多继承的复杂就干脆放弃了。 2什么是菱形继承多继承的问题是什么 菱形继承如字面意思两个父类的父类是同一个类就会发生菱形继承多继承本身没什么问题真正的问题是有多继承就可能发生菱形继承。菱形继承就有问题了变量的二义性和继承冗杂。解决办法很简单就是虚拟继承但是这样就会大大降低效率。 3继承和组合的区别什么时候用继承什么时候用组合 继承通过扩展已有的类来获得新功能的代码复用方法 组合新类由现有类的对象合并而成的类的构造方式 如果二者间存在一个“是”的关系并且一个类要对另外一个类公开所有接口那么继承是更好的选择 如果二者间存在一个“有”的关系那么首选组合!能用组合就用组合能用组合就用组合能用组合就用组合
http://www.dnsts.com.cn/news/177322.html

相关文章:

  • 网上书店网站建设毕业设计国家企业信息管理系统
  • 怎么查网站是不是百度做的杭州品牌vi设计公司
  • wordpress ajax国外seo综合查询
  • 捕鱼网站怎么做厦门seo报价
  • 网站建设网站推广优化网站如何进行备案
  • 免费的奖励网站有哪些资讯网站策划怎么写
  • 移动网站登录入口专业提供网站制作
  • 包头企业微网站开发升级网页
  • 网站介绍模版淘宝网站的建设情况
  • 购物网站建设开发重庆沙坪坝好玩的地方
  • 网站开发主题春考网页制作素材
  • 网站建设外包发展情况上海包装设计公司
  • 淘客那些网站怎么做的仿v电影的模板?好像是wordpress
  • 快速建设网站可以看男男做的视频网站
  • 商城网站模板 免费六安商城网站建设地址
  • 教育行业网站模板深圳做网站优化报价
  • 诸暨公司做网站wordpress自定義欄目
  • 企业电子商务网站建设的最终目的app要有网站做基础
  • 网站建设选信达互联传媒公司网站
  • 高校思政专题网站建设上海医院网站建设
  • 缙云企业网站建设自媒体营销平台
  • 怎样营销网站建设怎么做网站教程+用的工具
  • 张家港微网站中企动力做销售的感受
  • 福州网站建设方案电商怎么做账
  • 台州市建设厅网站网站建设核心
  • 网站源码安装推广营销软件
  • 如何免费建造网站百度seo搜索引擎优化
  • 1v1网站建设公司变更证明模板
  • 现在做网站用什么程序免费网站入口网站免费进ps软件
  • 网站多少流量够用河北新闻最新消息今天