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类图(上):类、继承和实现
面向对象设计 对于一个程序员来说,在工作的开始阶段通常都是别人把东西设计好,你来做.伴随着个人的成长,这个过程将慢慢变成自己设计一部分功能来实现,自己实现.如果要自己设计,无论是给自己看,还是给别人看 ...
随机推荐
- javascript文档DOC
python.java都有官网,有官方文档 javascript却找不到官网和官方文档 js大全 https://github.com/jobbole/awesome-javascript-cn md ...
- Light OJ 1296:Again Stone Game(SG函数打表找规律)
Alice and Bob are playing a stone game. Initially there are n piles of stones and each pile contains ...
- eclipse + cdt
Window > Preferences > General > Appearance中设置主题颜色. Help > eclipse marketplace > find ...
- web四则混合运算2
一.设计思路: 先出题(String型)(上周已经实现),再写方法计算结果,加入控制有无乘除法,范围,参与计算数,出题数,页码显示等简单功能,有无括号和分数的计算目前还没能实现. 二.代码: 界面 & ...
- LeetCode - Find K Closest Elements
Given a sorted array, two integers k and x, find the k closest elements to x in the array. The resul ...
- DBUtils和连接池
今日内容介绍 1.DBUtils 2.连接池 ###01DButils工具类的介绍个三个核心类 * A: DButils工具类的介绍个三个核心类 * a: 概述 * DBUtils是java编程中的数 ...
- xenserver使用快照创建虚拟机,提示eth0 has different mac错误
这个报错的意思就是说mac地址错误 我们对比后可以发现,用快照创建的虚拟机和原虚拟机的eth0那个配置文件的 mac地址是一样的,因为mac地址具有唯一性,所以就报这个错,无法配置ip上网 解决方法很 ...
- luarocks 自定义包发布试用
luarocks 是一个方便的lua 包管理工具,可以帮助我们实现代码的复用以及分享 注册账户 我使用了gihtub 的账户,直接点击&&授权即可 创建一个简单的luarocks 包项 ...
- 怎样优化app,看Facebook怎样做
周四,Facebook Engineering blog 发表了一篇名为<Improving Facebook on Android>博文.博文从四个方面(Performance,Data ...
- MT7628如何配置使用 Openwrt路由模式 (校园网配置)
1.设置wan,把网线插入wan口 1) 在 MT7628 开发板上的 3 个网口默认都是“LAN 口”功能,但拨号上网一般需要用到“WAN口”的功能,所以我们需要将其中一个切换为“WAN 口”,这里 ...