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

网站建设中哪个公司网站设计好

网站建设中,哪个公司网站设计好,采集发布wordpress,上海闵行区疫情最新情况本节课要点: 继承特性多态虚函数目录 一、多继承 二、继承的前提:正确的分类 三、多态 1. 虚函数 2. 确保覆盖和终止覆盖 3. 虚函数的实现原理 4. 虚析构函数 四、纯虚函数和抽象类 1. 纯虚函数 2. 抽象类 一、多继承 在之前的课程中&a…

本节课要点:

  • 继承
  • 特性
  • 多态
  • 虚函数

目录

一、多继承 

二、继承的前提:正确的分类 

三、多态

1. 虚函数

2. 确保覆盖和终止覆盖

3. 虚函数的实现原理

4. 虚析构函数 

四、纯虚函数和抽象类

1. 纯虚函数 

2. 抽象类 


一、多继承 

在之前的课程中,我们已经构建了自己的双向链表类。双向链表是一种线性表,线性表的作用是存储数据,故又称容器。学习了第六章:继承之后,我们会发现两者之间存在着Is-a关系,即双向链表是一种容器。因此,双向链表类应继承自容器类,即容器类是双向链表类的父类。 

下面考察 container 类(容器类) :

// container.h#pragma once#include "value_type.h"struct container {using value_type = ::value_type;using pointer = value_type*;using reference = value_type&;
};// traits
struct is_traversible {enum : bool {value = true}; // 枚举常量取的是bool值bool operator()() { // 这个重载使得结构体成为了可调用对象return value;}// 为了使用reference,把这段copy过来using value_type = ::value_type;using pointer = value_type*;using reference = value_type&;using callback = void (reference);
};

is_traversible 可遍历的,是所有容器共有的一种特性。

双向链表类继承容器类和特性类:

// dlist.h...class dlist : public container, public is_traversible { // 多继承
public:// typename container::value_type表明类型来自父类,typename指明这是一种类型using value_type = typename container::value_type;using pointer = typename container::pointer;using reference = typename container::reference;private:// 定义回调函数类型// using callback = void (reference);using is_traversible::callback;...};

特性介于继承和混入(mix-in)之间,但在C++中采用继承的方式来实现。

 

二、继承的前提:正确的分类 

考虑雇员、经理、销售员三者之间的关系,以下是一种错误的分类:

// employee.h#pragma once#include <iostream>
#include <string>class employee {
protected:job * j; // 赋值兼容原则public:const std::string name;// 只能在初始化列表初始化常量,否则就变成了赋值employee(job * j, const std::string& n) : j(j), name(n) {}~employee() {}void aboutme() {std::cout << name << ':' << j->title << std::endl;}
};class manager : public employee {using employee::employee; // 继承构造函数
};class salesperson : public employee {using employee::employee;
};

 修正后:

//employee.h#pragma once#include <iostream>
#include <string>struct job {std::string title;int salary;job(const std::string & t, int s) : title(t), salary(s) {}
};struct manager : public job {manager(int s = 10000) : job("manager", s) {}
};struct salesperson : public job {salesperson(int s = 5000) : job("salesperson", s) {}
};class employee {
protected:job * j;public:const std::string name;employee(job * j, const std::string& n) : j(j), name(n) {}~employee() {}void aboutme() {std::cout << name << ':' << j->title << std::endl;}
};

雇主和雇员是按照身份来分的,销售员和经理是按照职位来分的。

销售员和经理是一种角色(role),是可以互相转换的。而我们之前谈到的双向链表和数组是不会互相转换的,它们的关系铁铁的。

 

三、多态

回到之前的多边形类,我们试图求取各多边形的面积:

// poly.cpp#include <iostream>class poly {
protected://共性std::string ids;size_t edge;public:poly(std::string _ids = "poly", size_t e = 0) : ids(_ids), edge(e) {}~poly() {}std::string what() const {return ids;}double area() const {return 0.0;}
};class quad : public poly {
public:quad(std::string _ids = "quad") : poly(_ids, 4) {}~quad() {}
};class para : public quad {
protected:double width, height;public:para(double w = 1, double h = 1, std::string _ids = "para") : quad(_ids), width(w), height(h) {}~para() {}double area() const override {return width * height;}
};class rect : public para {
public:rect(double w = 1, double h = 1, std::string _ids = "rect") : para(w, h, _ids) {}~rect() {}
};class square final : public rect {
public:square(double w = 1) : rect(w, w, "square") {}~square() {}
};int main() {quad *quads[] = { new para(7, 4), new rect(10, 5), new square(8) };for (auto q : quads) {std::cout << q->what() << ' ' << q->area() << std::endl;delete q;}return 0;
}

输出结果:

para 0
rect 0
square 0

据分析,这里的三个形体使用的都是其父类 quad 的 area() 方法。原因是:我们使用的是父类 quad 的指针指向的子类对象,导致内存被重解释了。quad 认为自己指向的就是一个 quad 对象,因此便调用了父类子对象的 area() 方法。

因此,我们需要使用子类的方法覆盖父类的同原型方法。 

1. 虚函数

若要使子类的成员函数能够覆盖父类的同原型成员,则必须将父类的该成员说明是虚函数。关键字 virtual 明确地告诉编译器:这是一个虚函数;该类子类中的同名版本将覆盖这个版本。 

class poly {
protected:std::string ids;size_t edge;public:poly(std::string _ids = "poly", size_t e = 0) : ids(_ids), edge(e) {}~poly() {}std::string what() const {return ids;}virtual double area() const {return 0.0;}
};

虚特性能够被继承。如果子类原型一致地重载了父类的某个虚函数,那么即使在子类中没有将这个函数显式说明成是虚的,它也会被编译器认为是虚函数。 

 

2. 确保覆盖和终止覆盖

被 override 描述符修饰的函数明确地告诉编译器,自己是一个覆盖版本。 

class para : public quad {
protected:double width, height;public:para(double w = 1, double h = 1, std::string _ids = "para") : quad(_ids), width(w), height(h) {}~para() {}double area() const override {return width * height;}
};

final 描述符能有效终止虚函数的覆盖,或者后继继承的发生。 

class square final : public rect {
public:square(double w = 1) : rect(w, w, "square") {}~square() {}
};

 

3. 虚函数的实现原理

考察下述代码:

// sizeof-class-with-virtual.cpp#include <iostream>// alignof(类型) 向该类型对齐
class alignas(8) noVirtual { // align对齐 alignas(8)八字节对齐char a;void f() {}
};// 按道理来说,函数是不占类对象大小的
class alignas(8) oneVirtual {char a;virtual void f() {}
};class alignas(8) manyVirtual {char a;virtual void f() {}virtual int g() {return 0;}virtual double h(double) {return 1.0;}
};int main() {std::cout << "size of noVirtual: " << sizeof(noVirtual) << std::endl;std::cout << "size of oneVirtual: " << sizeof(oneVirtual) << std::endl;std::cout << "size of manyVirtual: " << sizeof(manyVirtual) << std::endl;std::cout << "ref: size of pointer: " << sizeof(void *) << std::endl;return 0;
}

输出结果:

size of noVirtual: 8
size of oneVirtual: 16 # 这多出的8个字节是编译器干的
size of manyVirtual: 16
ref: size of pointer: 8 # 给出参考:指针的大小

为了实现多态,编译器首先要为每个多态类创建一张虚表(VTABLE),表中记录了这个类的所有虚函数的入口地址。此外,编译器还在每一个多态类的对象中设置了一个虚指针(Virtual Pointer/VPTR),它指向了该类的虚表(VTABLE)。

 

4. 虚析构函数 

考察下述代码:

//normal-destructor.cpp#include <iostream>class X {
public:X() {std::cout << "X()" << std::endl;}~X() {std::cout << "~X()" << std::endl;}
};class Y : public X {
public:Y() {std::cout << "Y()" << std::endl;}~Y() {std::cout << "~Y()" << std::endl;}
};int main() {X *p = new Y;delete p;return 0;
}

输出结果:

X()
Y()
~X()

问题:这个对象没有完全被拆除

解决:设置父类的析构函数为虚函数

因为子类和父类占据的内存不一致,因此父类的析构函数不能被继承。

修正后:

class X {
public:X() {std::cout << "X()" << std::endl;}virtual ~X() {std::cout << "~X()" << std::endl;}
};

 

四、纯虚函数和抽象类

1. 纯虚函数 

public:poly(std::string _ids = "poly", size_t e = 0) : ids(_ids), edge(e) {}~poly() {}std::string what() const {return ids;}virtual double area() const = 0;
};

2. 抽象类 

// 狭义:只有类型定义和纯虚函数,广义:凡是拥有纯虚函数的类
struct container {using value_type = ::value_type;using pointer = value_type*; using reference = value_type&;virtual bool empty() const = 0;
};
http://www.dtcms.com/wzjs/179876.html

相关文章:

  • php 企业网站模板 想1淘宝seo优化是什么意思
  • 建设网站能解决什么问题你就知道首页
  • Wordpress自建外贸网站品牌网络营销策划
  • 新疆前昆工程建设集团网站6合肥网站关键词排名
  • wordpress如何修改后台路径内存优化大师
  • 网站上图片不能下载 该怎么做电商培训机构排名前十
  • 云适配 网站seo服务包括哪些
  • 做网站的公司算外包公司吗收录网
  • 织梦网站导入链接怎么做申请一个网站
  • 网站建设实训百度推广怎么推广
  • 哈尔滨网站优化页面百度账号登陆入口
  • wordpress配置搜索引擎优化推广
  • 如何用frontpage做网站网络公司关键词排名
  • 湘潭网站建设 h磐石网络企业培训考试
  • 园区网站建设crm系统
  • js特效网站欣赏seo站长工具查询
  • 成都企业网站设计制作好口碑关键词优化地址
  • 做整个网站静态页面多少钱湖南seo博客seo交流
  • 网站服务器好百度热线
  • 广东佛山seo是什么意思中文翻译
  • 网站开发与应用课程讨论东莞疫情最新通知
  • 两学一做专栏网站今天的新闻是什么
  • 建筑人才招聘网站大地资源网在线观看免费
  • 市场部做网站工作职责汕头seo优化项目
  • 学网站开发需要多长时间百度推广管理
  • 网站建设法律法规网站链接交易
  • 饮料公司网站模板seo网站优化专家
  • 嘉兴专业定制网站制作企业seo算法培训
  • 上海网站制作建设建设网站的步骤
  • 做网站头视频长沙营销推广