C++进阶--类的继承
//############################################################################
/*
* 公有,保护,私有继承
*/
class B {
};
class D_priv : private B { }; //私有继承
class D_prot : protected B { }; //保护继承
class D_pub : public B { }; //公有继承
/*
不同的继承方法指定了派生类对基类不同的访问控制权限
上述三个派生类:
1. 都不能访问B中的私有成员.
2. D_pub继承B中的公有成员为公有,继承B中的保护成员为保护
3. D_priv继承B中的公有保护成员为私有
4. D_prot继承B中的公有保护成员为保护
转换:
1. 任何人都可以将一个D_pub*转换为B*. D_pub是B的特殊情况
2. D_priv的成员和友元可以将D_priv*转成B*
3. D_prot的成员,友元及子女可以将D_prot*转成B*
注意:只有公有继承是is-a的关系
*/
/* 详细实例 */
class B {
public:
void f_pub() { cout << "f_pub is called.\n"; }
protected:
void f_prot() { cout << "f_prot is called.\n"; }
private:
void f_priv() { cout << "f_priv is called.\n"; }
};
class D_pub : public B { //对于公有继承
public:
void f() {
f_pub(); // OK. D_pub的公有成员函数
f_prot(); // OK. D_pub的保护成员函数
f_priv(); // Error. B的私有成员函数
}
};
class D_priv : private B { //对于私有继承
public:
using B::f_pub; //使其在D_priv的作用域内可见
void f() {
f_pub(); // OK. D_priv的私有成员函数
f_prot(); // OK. D_priv 的私有成员函数
f_priv(); // Error. B的私有成员函数
}
};
int main() {
D_pub D1;
D1.f_pub(); // OK. f_pub()是D_pub的公有成员函数
D_priv D2;
D2.f_pub(); // Error. f_pub()是D_priv的私有成员函数,增加using B::f_pub之后OK
B* pB = &D1; // OK 可以转换
pB = &D2; // Error 不能转换
...
}
//############################################################################
/*
* 私有继承: 类似于has-a关系,跟组合类似
*/
class Ring {
virtual tremble();
public:
void tinkle() {...; tremble(); }
};
/* 组合 */
class Dog {
Ring m_ring;
public:
void tinkle() {m_ring.tinkle();} // 向前调用
};
/* 私有继承*/
class Dog_Priv : private Ring {
public:
using Ring::tinkle;
};
/*
* 组合的优点: 比如可以有多个ring,ring可以切换 //通常情况下倾向于组合,更低耦合,更灵活
* 私有继承的优点:更优雅的多态,比如
*
* 在ring类中增加虚函数tremble(), 该函数在tinkle中被调用
*/
/*
* 公有继承 => "is-a" 关系
*
* 基类能做的任何事情,派生类需要也能做
*/
//像以下类的设计就是不合适的
class Bird {
public:
void fly();
};
class Penguin : public Bird {};
Penguin p;
p.fly();
// class flyableBird : public bird {};
// public:
// void fly();
//penguin p;
//p.fly();
// 看几个例子
class Dog {
public:
void bark() { cout << "Whoof, I am just a dog.\n";};
};
class Yellowdog : public Dog{
public:
void bark() { cout << "Whoof, I am a yellow dog.\n";};
};
int main() {
Yellowdog* py = new Yellowdog();
py->bark();
Dog* pd = py;
pd->bark();
}
OUTPUT:
Whoof, I am a yellow dog.
Whoof, I am just a dog.
/*
* 结论:不要覆写非虚函数
*/
class Dog {
public:
void bark(int age) { cout << "I am " << age; }
virtual void bark(string msg = "just a" ) {
cout << "Whoof, I am " << msg << " dog." << endl; }
};
class Yellowdog : public Dog {
public:
using Dog::bark;
virtual void bark(string msg="a yellow" ) {
cout << "Whoof, I am " << msg << " dog." << endl; }
};
int main() {
Yellowdog* py = new Yellowdog();
py->bark(5);
}
OUTPUT:
Whoof, I am a yellow dog.
Whoof, I am just a dog.
/*
* 不要重新定义虚函数的默认参数
* - 默认参数是静态绑定的
* - 虚函数是动态绑定的
*/
/*
* 在类dog中增加如下函数:
* virtual void bark(int age) { cout << "I am " << age << " years old"<< endl; }
* in main(),
* py->bark(5); // 编译不过
* // 可以通过在yellowdog中加"using Dog::bark;"修复 为了保持is-a关系
*/
// 防止意外覆写,或者没有覆写,增加了override关键字
class Dog {
public:
virtual void bark() { cout << "I am just a dog.\n";};
void run();
};
class Yellowdog : public Dog{
public:
virtual void barks() { cout << "I am a yellow dog.\n";}; //在旧标准中不会报错,等出错了调试比较困难
};
// C++ 11 standard:
class Yellowdog : public Dog{
public:
virtual void barks() override;
// 编译错误:没有覆写的函数
virtual void bark() const override;
// 编译错误:没有覆写的函数
void run() override; // 压根不是虚函数,错误
};
/*
* 避免采坑:
* 1. 类的精确定义
* 2. 不要覆写非虚函数
* 3. 不要覆写虚函数的默认参数
* 4. 强制继承被遮盖的函数
* 5. 小心函数覆写时的错字
*/
C++进阶--类的继承的更多相关文章
- Python类的继承(进阶5)
转载请标明出处: http://www.cnblogs.com/why168888/p/6411918.html 本文出自:[Edwin博客园] Python类的继承(进阶5) 1. python中什 ...
- 苹果新的编程语言 Swift 语言进阶(十)--类的继承
一.类的继承 类能够从其它类继承方法.属性以及其它特性,当一个类从另外的类继承时,继承的类称为子类,它继承的类称为超类.在Swift中,继承是类区别与其它类型(结构.枚举)的基础行为. 1.1 .类的 ...
- Java+7入门经典 - 6 扩展类与继承 Part 1/2
第6章 扩展类与继承 面向对象编程的一个重要特性: 允许基于已定义的类创建新的类; 6.1 使用已有的类 派生 derivation, 派生类 derived class, 直接子类 direct s ...
- Javascript 进阶 面向对象编程 继承的一个样例
Javascript的难点就是面向对象编程,上一篇介绍了Javascript的两种继承方式:Javascript 进阶 继承.这篇使用一个样例来展示js怎样面向对象编程.以及怎样基于类实现继承. 1. ...
- Javascript 进阶 面向对象编程 继承的一个例子
Javascript的难点就是面向对象编程,上一篇介绍了Javascript的两种继承方式:Javascript 进阶 继承,这篇使用一个例子来展示js如何面向对象编程,以及如何基于类实现继承. 1. ...
- 游戏编程之Unity常用脚本类的继承关系
前言学习Unity开发引擎的初学者会接触大量的脚本类,而这些类之间的关系往往容易被忽略.本文对Unity引擎开发中的一些常用类及其关系进行了简单的归纳总结. 博文首发地址:http://tieba.b ...
- Objective-C编程 — 类和继承
讲述面向对象中的一个重要概念——继承,使用继承 可以方便地在已有类的基础上进行扩展,定义一个具有父 类全部功能的新类. 父类和子类 我们在定义一个新类的时候,经常会遇到要定义的新类是某个类的扩展或者是 ...
- C++学习笔记:07 类的继承与派生
课程<C++语言程序设计进阶>清华大学 郑莉老师) 基本概念 继承与派生的区别: 继承:保持已有类的特性而构造新类的过程称为继承. 派生:在已有类的基础上新增自己的特性(函数方法.数据成员 ...
- UML类图(上):类、继承和实现
面向对象设计 对于一个程序员来说,在工作的开始阶段通常都是别人把东西设计好,你来做.伴随着个人的成长,这个过程将慢慢变成自己设计一部分功能来实现,自己实现.如果要自己设计,无论是给自己看,还是给别人看 ...
随机推荐
- [LeetCode&Python] Problem 429. N-ary Tree Level Order Traversal
Given an n-ary tree, return the level order traversal of its nodes' values. (ie, from left to right, ...
- OpenCV2类批量处理文件夹及文件图像 及批量处理后保存到txt文件
//采用windows控制台实现计算文件夹中对象总数以及批量读取对象 //#include <afx.h> //和windows.h是一样的作用 #include <opencv2/ ...
- unity中实现简单对象池,附教程原理
Unity对象池的创建与使用 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享 ...
- cglib实现动态代理简单使用
Boss: package proxy.cglib; public class Boss{ public void findPerson() { System.out.println("我要 ...
- hibernate--DetachedCriteria(离线条件查询)
一.叙述 离线条件查询的好处,可以在非dao层封装查询参数,封装完成后,将对象传递到dao层,关联到session后,再去查询数据,这样做dao层可以极大的简化代码.下面通过一个小案例,一起来感受一下 ...
- java 8大数据类型
第一类:逻辑型boolean 第二类:文本型char 1.JAVA中,char占2字节,16位.可在存放汉字 2.char赋值 char a='a'; //任意单个字符,加单引号. char a=' ...
- 【java多线程】java8的流操作api和fork/join框架
原文:https://blog.csdn.net/u011001723/article/details/52794455/ 一.测试一个案例,说明java8的流操作是并行操作 1.代码 package ...
- 【liunx】linux后台执行命令:&和nohup
当我们在终端或控制台工作时,可能不希望由于运行一个作业而占住了屏幕,因为可能还有更重要的事情要做,比如阅读电子邮件.对于密集访问磁盘的进程,我们更希望它能够在每天的非负荷高峰时间段运行(例如凌晨).为 ...
- webpack中hash、chunkhash、contenthash区别
webpack中对于输出文件名可以有三种hash值: 1. hash 2. chunkhash 3. contenthash 这三者有什么区别呢? hash 如果都使用hash的话,因为这是工程级别的 ...
- doubleclick video notes
1,vast duration it must math this format ,if use “00:00:7 ” it will tip “ ” <Duration>00:00:0 ...