C++ 特性

C++ 三大特性,封装继承多态。我们先实现一个Quote作为基类

class Quote
{public:Quote() = default;Quote(const std::string &book, double sales_price){price = sales_price;bookNo = book;}std::string isbn() const{return bookNo;}virtual double net_price(std::size_t n) const{cout << "this is Quote net_price" << endl;return n * price;}static void PrintHello(){cout << "hello world" << endl;}Quote(const Quote &quote) : bookNo(quote.bookNo), price(quote.price) {}void printMem(){cout << "price is " << price << " bookNo is " << bookNo << endl;}virtual ~Quote(){cout << "this is Quote destruct" << endl;}// final 阻止其他继承Quote的类重写f3函数virtual void f3() final {}private:std::string bookNo;protected:double price = 0.0;
};

net_price是一个虚函数,实现了基类的计算规则。同时我们实现了一个虚函数f3,但是f3末尾用final标识了,表示继承Quote的子类不能重写f3函数。
我们实现子类

class BulkQuote : public Quote
{public:BulkQuote() = default;BulkQuote(const std::string &book, double p, std::size_t qty, double disc) : Quote(book, p), min_qty(qty), discount(disc){}// override 是C11提供的继承关系检测工具,检测函数类型是否匹配,是否为虚函数等。double net_price(std::size_t) const override;// void f3() {}private://打折后最多买多少std::size_t min_qty = 0;//折扣额度double discount = 0.0;
};

子类无法重写f3所以注释了。子类BulkQuote重写了net_price,该函数后边用了overide关键字,C11规定写了override关键字的函数必须符合基类的规则,包括函数参数类型相同,返回值相同,函数名一致等。
基类Quote有一个静态函数PrintHello,子类继承Quote也将PrintHello继承过来。
可以通过如下方式调用

void use_base_static()
{Quote::PrintHello();BulkQuote::PrintHello();
}

可以将子类赋值给基类或者将子类对象传给基类的构造函数,这么做的结果是基类构造时只拷贝子类的基类部分。

void use_derive_to_base()
{BulkQuote bulkquote(string("Live"), 1.2, 100, 0.8);//子类传给基类构造函数,或者子类赋值给基类//就会调用基类构造函数,只构造基类部分。Quote quote(bulkquote);quote.printMem();quote = bulkquote;quote.printMem();
}

当我们将一个子类对象传递给一个基类引用,或者将一个子类对象的指针传递给一个基类指针,通过基类的指针或引用调用虚函数,会动态调用子类对象的虚函数版本,这种特性叫做多态。我们先实现一个全局函数

void print_total(ostream &os, const Quote &quote, std::size_t n)
{os << quote.net_price(n) << endl;
}

多态特性会让编译器根据动态类型绑定虚函数调用的版本,所谓动态类型就是运行时才确定的类型。

void use_derive_param()
{BulkQuote bulkquote(string("Live"), 1.2, 100, 0.8);Quote quote(string("Quote"), 1.2);print_total(cout, quote, 100);print_total(cout, bulkquote, 100);
}

上面的程序会根据传给print_total具体的实参类型调用各自的虚函数net_price。

纯虚类

如果一个类只包含纯虚函数,不包含成员变量,则该类为纯虚类。所谓纯虚函数就是只有声明,函数体为=0的形式。

//纯虚类
class VirtualBase
{public:VirtualBase() = default;virtual void mem() = 0;virtual void test() = 0;
};

纯虚类类似于Go语言的interface,当我们继承纯虚类后一定要重写其所有的纯虚函数。

class DeriveFromBase : public VirtualBase
{virtual void mem(){}virtual void test() {}
};

封装性

子类只可以访问基类的protected和public成员,不能访问private成员。子类的友元函数可以访问子类的私有变量,公有变量以及受保护的变量,当时不能访问基类的私有变量和protected变量。

// protected
class ProBase
{public:ProBase() = default;ProBase(int n) : prot_mem(n) {}void mem_func(){cout << "this is ProBase mem_func" << endl;}protected:int prot_mem;private:int priv_mem;
};

ProBase包括一个私有变量priv_mem和一个受保护变量prot_mem。我们定义子类继承它

class Sneaky : public ProBase
{public:Sneaky() = default;Sneaky(int n) : ProBase(1024), prot_mem(n) {}//子类可以使用基类的public和protected成员void UsePro(){cout << prot_mem << endl;}//子类无法使用基类的private成员。// void UsePriv()// {//     cout << priv_mem << endl;// }friend void clobber(Sneaky &);friend void clobber(ProBase &);void GetMem(){cout << "this is ProBase prot_mem: " << ProBase::prot_mem << endl;cout << "this is Sneaky prot_mem: " << prot_mem << endl;}void mem_func(int n){cout << "this is Sneaky mem_func" << endl;}private:int self_mem;int prot_mem;
};

通过继承Sneaky拥有了基类ProBase的私有变量priv_mem和受保护变量prot_mem。又定义了自己的私有变量self_mem和prot_mem。
可以看到即使在Sneaky的类声明中UsePriv这个函数里也无权访问基类的私有变量priv_mem。我们在如下函数测试

void use_probase()
{Sneaky sk(11);// sk.prot_mem;sk.GetMem();//调用子类的mem_func(int n)sk.mem_func(100);ProBase pb;//调用基类的mem_func()pb.mem_func();//基类的mem_func()被覆盖了//sk.mem_func();//想使用基类的mem_func()需要添加基类作用域sk.ProBase::mem_func();
}

在类的声明之外,通过对象的方式无法直接使用sk的私有变量prot_mem。因为子类实现了mem_func(int n)版本,所以把基类的mem_func(void)覆盖了,想调用基类版本的mem_func()需要通过sk.ProBase::mem_func()显示调用基类版本。
接下来我们实现Sneaky的两个友元函数

void clobber(Sneaky &s)
{s.prot_mem = 100;s.self_mem = 1000;
}
//子类友元无法访问基类受保护成员
void clobber(ProBase &b)
{// b.prot_mem = 10;
}

子类的友元函数无法访问基类的私有成员和保护成员。

重写和隐藏

子类继承基类,重新实现基类的虚函数就叫做重写,重写要求必须和基类的虚函数完全匹配,包括参数类型返回值等。
对于基类的非虚函数,子类实现了同名的函数,只要名字相同,即使参数不同,也可以覆盖基类函数,叫做隐藏。

class VBase
{public:virtual int fcn(){cout << "this is VBase fcn()" << endl;}
};class VD1 : public VBase
{public:// VD1自己定义的fcn(int),因为和基类VBase的fcn参数不同//但是VD1也继承了VBase  fcn()这个版本//隐藏了基类的fcn()int fcn(int){cout << "this is VD1 fcn(int)" << endl;}// VD1自己新定义的虚函数virtual void f2(){cout << "this is VD1 f2()" << endl;}
};class VD2 : public VD1
{public://隐藏了VD1版本的fcn(int),因为VD1中fcn(int)不是虚函数int fcn(int){cout << "this is VD2 fcn(int)" << endl;}//重写,因为VD1从VBase中继承了虚函数fcn()int fcn(){cout << "this is VD2 fcn()" << endl;}//重写了VD1的虚函数void f2(){cout << "this is VD2 f2()" << endl;}
};

如下函数展示了覆盖和重写等情况时调用规则

void use_hiddenbase()
{VD1 vd1;//调用基类VBase版本vd1.VBase::fcn();//调用VD1版本vd1.fcn(100);VD2 vd2;VBase *pvb = &vd1;//会调用基类的VBase::fcn()pvb->fcn();VBase *pvb2 = &vd2;//多态调用VD2::fcn()pvb2->fcn();VD1 *pvd1 = &vd2;//调用VD2版本的f2()pvd1->f2();
}

类的继承和多态总结

1 派生类向基类转换只在指针或引用时才生效
2 不存在默认的基类向子类转换,但是如果确认转换安全可以通过static_cast来转换。
3 类不想被继承,可以在类名后添加final关键字
4 如果子类无权访问基类构造函数,则无法实现子类对象向基类对象的转换。
5 子类对象可以向基类对象转换,默认只将子类对象中基类的成员赋值给基类对象。
6 多态就是将子类对象的指针赋值给基类对象的指针,通过调用基类的虚函数,实现动态绑定, 运行时调用了子类的虚函数。

7 final 声明的虚函数会阻止继承该类的类重写该函数
8 override 要求编译器检测重写的函数是否符合规则,是否为虚函数,是否为类型相同。
9 继承纯虚类,一定要实现它的所有纯虚方法,否则该类无法使用。
10 子类可以使用基类的public和protected成员,子类无法使用基类的private成员
11 proteced 和private成员不可被对象的方式访问。
12 子类的友元函数可以访问子类的私有变量和受保护变量,但是不能访问基类的受保护变量。
13 子类的友元函数可以访问子类自己定义的私有变量,但是不能访问从基类继承而来的私有变量。
14 子类和基类有相同名字的成员或者非虚函数非静态的成员函数,在使用的时候默认使用子类的,
如果想使用基类的需要加上基类名字的作用域。
15 如果子类实现的函数和基类的虚函数同名,但是参数类型不同,就不是重写而是隐藏,重写要求子类的函数和
基类的虚函数类型,名称完全一致。
16 针对一个普通的非虚函数的成员函数,子类实现了一个同名的函数,就是覆盖,会隐藏基类的同名函数
17 重载是对于一个类来讲,实现了多个同名函数,他们的参数不同。

C++ 类的封装继承多态相关推荐

  1. python--编写程序:实现乐手弹奏乐器,乐手可以弹奏不同的乐器而发出不同的声音------使用类的封装继承多态的问题/使用面向对象的思想,设计自定义类,描述出租车和家用轿车的信息

    编写程序:实现乐手弹奏乐器,乐手可以弹奏不同的乐器而发出不同的声音 ------使用类的封装继承多态的问题 class Instrumnet():#乐器类def make_sound(self):pa ...

  2. 类的封装继承多态以及virtual interface-SV

    文章目录 一.面向对象 1.1术语 1.2 三大特性和五大原则 1.3 验证为什么需要OOP 二.类和对象 2.1浅复制shallow copy 2.2 深复制(deep copy) 三.类的封装和继 ...

  3. c语言编程 菲薄拉,C语言设计模式-封装-继承-多态

    快过年了,手头的工作慢慢也就少了,所以,研究技术的时间就多了很多时间,前些天在CSDN一博客看到有大牛在讨论C的设计模式,正好看到了,我也有兴趣转发,修改,研究一下. 记得读大学的时候,老师就告诉我们 ...

  4. python 参数类型的多态_【Python】面向对象:类与对象\封装\继承\多态

    六.Python面向对象--类与对象\封装\继承\多态 1.什么是面向对象编程 1.1 程序设计的范式:程序可控,易于理解 1.2 抽象并建立对象模型 1.3 程序是不同对象相互调用的逻辑.每个对象在 ...

  5. Java继承_Hachi君浅聊Java三大特性之 封装 继承 多态

    Hello,大家好~我是你们的Hachi君,一个来自某学院的资深java小白.最近利用暑假的时间,修得满腔java语言学习心得.今天小宇宙终于要爆发了,决定在知乎上来一场根本停不下来的Hachi君个人 ...

  6. python多态的三种表现形式_python小结----面向对象的三大特征(封装,继承,多态)

    面向对象的三大特征: 封装,继承,多态 面向对象的编程思想核心:高类聚,低耦合–程序的设计模式范畴 封装 什么是封装: 在面向对象编程的思想中,对代码进行高度封装,封装又叫包装 封装就是指将数据或者函 ...

  7. 大数据笔记8—java基础篇4(面向对象-封装-继承-多态)

    面向对象 一.面向对象 1.面向过程 1.2.举例 1.3.总结 二.面向对象 1.简述 2.举例 3.思想特点 2.1.类的定义格式 2.1.1.简述 2.2.2.格式 2.3.3.示例 三.类的使 ...

  8. 小白理解——封装继承多态

                                      一.封装 是什么:首先是抽象,把事物抽象成一个类,其次才是封装.对外表示为一个对象,隐藏对象的属性和动作实现的细节,仅对外公开接口. ...

  9. Day55-每日一道Java面试题-Java 面向对象编程三大特性: 封装 继承 多态

    Java 面向对象编程三大特性: 封装 继承 多态 封装 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问.但是如果一个类没有 ...

  10. 面向对象 编程及面向对象三大属性:封装 继承 多态

    面向对象 面向对象(Object Oriented,OO)是软件开发方法.面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统.交互式界面.应用结构.应用平台.分布式系统.网络管理结构. ...

最新文章

  1. 系统吞吐量(TPS)、用户并发量、性能测试概念和公式(转载)
  2. OSPF协议学习笔记(一)
  3. 配置Tomcat监听80端口 配置Tomcat虚拟主机 Tomcat日志
  4. mysql 物理备份工具_mysql物理备份工具Xtrabackup安装配置
  5. java 上传视频并播放_java实现视频上传和播放..doc
  6. mac+php7+mysql.so_在Mac上编译安装PHP7的开发环境
  7. boost::mp11::mp_any_of_q相关用法的测试程序
  8. dockerfile使用(一)
  9. 安卓学习笔记38:利用OpenGL ES绘制旋转立方体
  10. JAVA互联网应用架构师、JAVA架构、JAVA中间件、集群等互联网应用
  11. Retrofit 使用flatmap操作符时处理错误、异常
  12. php和jsp有什么区别,php和jsp之间的区别是什么
  13. 台式计算机时间不能同步,台式电脑时间同步不了?一分钟就能快速解决
  14. 举个栗子!Tableau 技巧(86):用 ZN 函数处理数据缺失点
  15. 最后一课——没有拥抱,已成永远
  16. npm ERR path /Users/user/Desktop/app/node_modules/node-sass
  17. typora 公式对齐_Typora极简教程
  18. 语义分割指标---MIoU详细介绍(原理及代码)
  19. 王某与石某的分歧卡卡罗特
  20. TCP协议:SYN、ACK、ISN、SeqNumber

热门文章

  1. 哪个手机浏览器支持html5,四大手机浏览器HTML5兼容性横评
  2. viper12a电源电路图_viper12a引脚功能图与引脚电压
  3. 单片机实验13:用热敏电阻和ADC实现测量温度
  4. Iometer存储测试工具参数说明-4test setup
  5. 软件测试(七):自动化测试、安全测试、性能测试
  6. Spring实战——FileSystemResource
  7. 非线性鲁棒控制器_Sliding Mode_滑模控制
  8. DPDK Release 20.05
  9. 网易电子邮箱的文档功能是什么?
  10. 计算机二级C语言考试模拟系统+真题题库软件下载