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

免费建立平台网站做内贸哪个网站好

免费建立平台网站,做内贸哪个网站好,wordpress显示近几篇微博,秦皇岛黄金海岸游玩攻略文章目录继承继承的概念继承方式及权限using改变成员的访问权限基类与派生类的赋值转换回避虚函数机制派生类的默认成员函数友元与静态成员多继承菱形继承虚继承组合继承 继承的概念 继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。 当创建一个类时我们可以继承一个已有类的成员和方法并且在原有的基础上进行提升这个被继承的类叫做基类而这个继承后新建的类叫做派生类。基类必须是已经定义而非仅仅声明因此一个类不能派生它本身。 继承这种通过生成子类的复用通常被称为 白箱复用(white-box reuse) 。术语 白箱 是相对可视性而言在继承方式中父类的内部细节对子类可见。 派生类的作用域嵌套在基类的作用域之内。 class [派生类名] : [继承类型] [基类名][继承类型] [基类名] 的组合被称为派生列表值得注意的是派生列表仅出现在定义中而不能出现在声明中 class A : public B; // ERROR派生列表不能出现在声明中正确实现如下 class Human { public:Human(string name 张三, int age 18) : _name(name), _age(age){}void Print(){cout name: _name endl;cout age: _age endl;}protected:string _name;int _age; };class Student : public Human { public:Student(string stuNum 123456) : Human(), _stuNum(stuNum){}void Print() // 将父类的Print函数重定向成自己的Print函数{Human::Print();cout stuNum: _stuNum endl;}protected:string _stuNum; // 增加的成员变量 };int main() {Human h1;Student s1;h1.Print();cout endl;s1.Print();return 0; }基类和派生类都具有他们各自的作用域那如果出现同名的成员如上面的 Print函数 此时会怎么样呢这里就要牵扯到一个概念——隐藏。隐藏而非 重载 方法名虽然相同但处于不同的作用域中。 隐藏也叫做重定义当基类和派生类中出现重名的成员时派生类就会将基类的同名成员给隐藏起来然后使用自己的。但是隐藏并不意味着就无法访问可以通过声明基类作用域来访问到隐藏成员。) 因此 s1 调用 Print函数 时不会调用父类的而是调用自己的。 继承方式及权限 继承的方式和类的访问限定符一样分为 public(公有继承)、private(私有继承)、protected(保护继承) 三种。 关于 protected 对于类的对象来说是不可访问的。 class Human { private:int pri; protected:int pro; public:int pub; };对于派生类的成员数据成员or成员函数和基类的友元来说是可以访问的。 子类/子类的友元不能直接访问父类的受保护成员只能通过子类对象来访问。 如果子类及其友元能直接访问父类的受保护成员那么 protected 提供的访问保护也就太不安全了。 class Human { protected:int age; };class Student : public Human {int stu_id;friend void get(Human); // 不能访问Human::agefriend void get(Student); // 可以访问Student:age };基类成员的访问说明符/派生类的继承方式 对基类成员的访问权限只与基类中的访问说明符有关与派生类的继承方式无关。 class Human { private:int pri; protected:int pro; public:int pub;friend int f(Human h) { return h.pro; } };class Student : public Human {int f1() { return pri; } // ERROR纵然是public继承也不可以访问private成员int f2() { return pro; } // 正确protected成员可以被派生类访问 };class Teacher : private Human {int f1() { return pro; } // 正确protected成员可以被派生类访问即使继承方式是private };继承方式控制派生类对象包括派生类的派生类对于基类成员的访问权限。 总结来讲父类成员的访问权限决定了子类是否能访问该成员而继承方式决定了父类成员在子类中的新权限是怎样的 public继承自父类的成员在父类中是什么权限子类中就是什么权限。protected继承自父类的成员其访问权限都变成 protected。private继承自父类的成员其访问权限都变成 private。 派生类向基类转换的可访问性 假设 D 继承自 B 只有当 D 公有地继承 B 时派生类对象才能使用派生类向基类的转换如果继承方式是受保护的或者私有的则不能使用该转换。不论 D 以什么方式继承 BD 的成员函数和友元都能使用派生类向基类的转换。换言之派生类向其直接基类的类型转换对于派生类的成员和友元来说永远是可访问的。如果继承方式是公有的或者受保护的则D的子类第二点说的是D本身的成员和友元可以使用 D 向 B 的类型转换反之如果继承方式是私有的则不能使用。 默认的继承方式 默认情况下 使用 class 关键字定义的派生类是私有继承的使用 struct 关键字定义的派生类是公有继承的 using改变成员的访问权限 我们说继承方式决定了派生类的对象及派生类的子类对继承来的成员的访问权限但这不是绝对的我们可以通过 using 改变成员的访问权限但只能改变派生类能访问的成员即基类中的 protected 和 public 成员。 class Human { private:int pri; protected:int pro; public:int pub; };class Teacher : private Human { // 私有继承 private:// 只能被类的成员or友元访问 public:using Human::pri; // 错误using只能为派生类可访问的成员提供声明using Human::pro; // Teacher的对象、成员、友元、子类都可以访问 protected:using Human::pro; // Teacher的对象、成员、友元可以访问using Human::pub; };基类与派生类的赋值转换 我们在 四种强制转换类型中的 dynamic_cast 部分 提到过父类与子类的赋值转换 派生类可以赋值给基类的对象、指针或者引用这样的赋值也叫做 对象切割 。 当把派生类赋值给基类时可以通过切割掉多出来的成员如 _stuNum 来完成赋值。 但是 基类对象 不可以赋值给 派生类 因为他不能凭空多一个 _stuNum 成员出来。 但是 基类的指针却可以通过强制类型转换赋值给派生类对象 如 int main() {Human h1;Student s1;Human* hPtrs s1; // 指向派生类对象Human* hPtrh h1; // 指向基类对象// 传统方法Student* pPtr (Student*)hPtrs; // 没问题Student* pPtr (Student*)hPtrh; // 有时候没有问题但是会存在越界风险// 如果父类之中包含虚函数可以使用dynamic_castStudent* pPtr dynamic_castStudent*(hPtrh);// 如果确认基类向派生类的转换是安全的可以使用static_castStudent* pPtr static_castStudent*(hPtrs);return 0; } 总结来讲 派生类可以赋值给基类的对象、指针或者引用基类对象不能赋值给派生类对象基类的指针可以通过强制类型转换赋值给派生类的指针。但是必须是基类的指针是指向派生类对象时才是安全的否则会存在越界的风险。但基类如果是多态类型父类之中包含虚函数则可以使用 RTTI 的 dynamic_cast 来实现 指向基类的基类指针 到 派生类对象 的安全转换。 回避虚函数机制 我们说多态是为了实现子类对于同一操作的不同结果但有时候派生类需要调用其父类的虚函数版本而非自己的虚函数版本 int main() {Human h1;Student s1;Human* hPtrs s1; // 指向派生类对象hPtrs-print(); // 由于hPtrs指向子类对象因此调用子类的虚函数hPtrs-Human::print(); // 强行调用Human中的虚函数而不在意hPtrs的动态类型return 0; }派生类的默认成员函数 之前有写过 类的默认六个成员函数 class Human { public:Human(){cout Human 构造函数 endl;}~Human(){cout Human 析构函数 endl;}protected:string _name;int _age; };class Student : public Human { public:Student(){cout Student 构造函数 _name endl;}~Student(){//~Human(); 不需要手动调用父类的析构函数编译器会在子类析构函数结束后自动调用。cout Student 析构函数 endl;} protected:string _stuNum; };int main() {Student s1;return 0; } 可以看到调用派生类的默认成员函数时都会调用基类的默认构造函数。 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数则必须在派生类构造函数的初始化列表阶段显示调用。派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。派生类的 operator 必须要调用基类的 operator 完成基类的复制。派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。 在派生类的析构函数中基类的析构函数会被隐藏为了实现多态它们都会被编译器重命名为 destructor 。 友元与静态成员 友元 友元关系是不会继承的友元关系不具有传递性可以这样理解你长辈的朋友并不是你的朋友。 基类的友元能访问基类的私有/保护成员但不能访问子类的私有/保护成员。当然基类本身也无法访问子类的私有成员。子类访问父类友元的私有成员就更不用想了 一是友元关系并不对称A 是 B 的友元B 不一定是 A 的友元也就是说父类本身都不一定能访问父类友元的私有成员父类不一定是其友元的友元何况子类二是就算父类是其友元的友元但友元关系不具有传递性子类不一定是父类友元的友元。 子类的友元无法访问父类的私有/保护成员。 静态成员 无论继承了多少次派生了多少子类静态成员在这整个继承体系中有且只有一个。静态成员不再单独属于某一个类亦或者是某一个对象而是属于这一整个继承体系。 多继承 如果一个子类同时继承两个或以上的父类时此时就是多继承。 多继承虽然能很好的继承多个父类的特性达到复用代码的效果但是他也有着很多的隐患例如菱形继承的问题这也就是为什么后期的一些语言如 java 把多继承去掉的原因。 菱形继承 class Human { public:int _age; };class Student : public Human { public:int _stuNum; };class Teacher : public Human { public:int _teaNum; };这里有着人类、学生类、老师类。在学校中还存在着同时具有老师和学生这两个属性的人也就是助教。所以我们可以让他同时继承 teacher类 和 student类 。 class Assistant : public Teacher, public Student { };按照道理来说各个类的大小应该是这样的。Human 类4个字节Teacher 和 Student 都是8个字节而 Assistant 是12个字节。但是实际上 Assistant 却是16字节。 这就是菱形继承的 数据冗余 和 二义性 问题的体现。 这里的 Teacher 和 Student 都从 Human 中继承了相同的成员 _age 。但是 Assistant 再从 Teacher 和 Student 继承时就分别把这两个 _age 都给继承了过来。 这就是数据冗余问题。 倘若我们想要给那个 _age 赋值 因为里面存在两个一样的 _age 因此需要指定作用域 这也就是二义性问题。 虚继承 想解决二义性很简单当多个类继承同一个类时就在继承这个类时为其添加一个虚拟继承的属性。 class Student : virtual public Human { public:int _stuNum; };class Teacher : virtual public Human { public:int _teaNum; };这时就可以看到它只继承了一次。 接下来看看大小 按照道理来说a 应该是 12字节t 、 s 应该是 8字节 啊这里就牵扯到了C的对象模型先推荐一篇博客 C中的虚函数(表)实现机制以及用C语言对其进行的模拟实现 这里多出来的 8个字节其实是两个虚基表指针(vbptr)。同理s 、t 多出来的 4字节是 一个vbptr 。 因为这里 Human 中的 _age 是 teacher 和 student 共有的所以为了能够方便处理在内存中分布的时候就会把这个共有成员 _age 放到对象组成的最末尾的位置。然后在建立一个虚基表这个表记录了各个虚继承的类在找到这个共有的元素时在内存中偏移量的大小而虚基表指针则指向了各自的偏移量。 这里打个比方 通过这个偏移量他们能够找到自己的 _age 的位置。 为什么需要这个偏移量呢 int main() {Assistant a;Teacher t a; Student s a;return 0; }如上当把对象 a 赋值给 t 和 s 的时候因为他们互相没有对方的 _stuNum 和 _teaNum所以他们需要进行对象的切割但是又因为 _age 存放在对象的最尾部所以只有知道了自己的偏移量才能够成功的在切割了没有的元素时还能找到自己的 _age 。 组合 那除了继承还有什么好的代码复用方式吗那答案肯定是有的就是组合。组合就是将多个类组合在一起实现代码复用。 继承和组合又有什么区别呢 继承是一种 is a 的关系基类是一个大类而派生类则是这个大类中细分出来的一个子类但是他们本质上其实是一种东西。正如学生也是人所以他可以很好的继承人的所有属性并增加学生独有的属性。组合是一种 has a 的关系就是一种包含关系。对象a 是 对象b 中的一部分对象b 包含 对象a 。 组合这种通过对方开放接口来实现的复用被称为 黑箱复用(black-box reuse)因为对象的内部细节是不可见的。对象只以 黑箱 的形式出现。 class Study { public:void ToStudy(){cout Study endl;} };class Student : public Human { public:Study _s;int _stuNum; };这里的 Student类 中包含了一个 Study类 学习是学生日常生活中不可缺少的一部分。 比较组合和继承 组合的依赖关系弱耦合度低。保证了代码具有良好的封装性和可维护性。 在组合中几个类的关联不大我只需要用到你那部分的某个功能我并不需要了解你的实现细节只需要你开放对应的接口即可并且如果我要修改只修改那一部分功能即可。继承的依赖关系就非常的强耦合度非常高。 因为你要想在子类中修改和增加某些功能就必须要了解父类的某些细节并且有时候甚至会修改到父类父类的内部细节在子类中也一览无余严重的破坏了封装性。并且一旦基类发生变化时牵一发而动全身所有的派生类都会有影响这样的代码维护性会非常的差。一个可用的解决方法就是只继承抽象类因为抽象类通常提供较少的实现。 但是大部分场景下如果继承和组合都可以选择那么 优先使用对象组合而不是类继承 。
http://www.sadfv.cn/news/317921/

相关文章:

  • 有没有网站教做美食的网站首页页脚设计
  • 广告设计就业方向口腔医院网站做优化
  • 全国招聘网站排名侵入别人的网站怎么做
  • 盘锦威旺做网站建设公司dw网站模板免费下载
  • 菏泽网站建设服务婚介 东莞网站建设
  • 网站建设费用是什么科目网站建设大
  • 12306网站建设网页设计培训班学费多少钱
  • 网站关联页面如何做wordpress网站域名服务器
  • 网站登录界面模板html湖北工程建设信息网官网
  • 海沧网站建设乐山建网站
  • 乾安网站建设哪家好网络 网站建设办公
  • 制作网站注册页面模板产品推广图片
  • 网站 seo优化深圳燃气公司上班时间
  • 建设网站涉及的技术宣传型企业网站
  • 百度知道入口seo优化培训学校
  • 网站建设报告 商业价值新建的网站打不开
  • django做网站比较容易邢台兼职网站有哪些?
  • 网络网站制作技巧音乐播放器网站怎么做
  • 金昌大型网站建设费用wordpress 登录用户
  • 网站信任 用户转化wordpress 请提供有效的用户名.
  • 软件程序员重庆网站seo设计
  • iis做网站文件下载海南茶叶网站建设
  • 外国建筑网站河南省建设厅网网站首页
  • 绵阳做公司网站郑州网站建设套餐
  • 微信网站模板免费下载莱芜招聘网
  • 珠海找工作哪个网站好网站开发遇到的风险
  • 为什么建设法律法规网站佛山顺德网站建设公司哪家好
  • 手机免费创建网站的软件抖音网络推广怎么做
  • 合肥网站seo推广技术开发
  • 汕头网站推广教程腾讯建设网站首页