c++ 派生类向基类转换的可访问性
对于c++面向对象一直很疑惑,这次决定下功夫把它弄明白
一、派生类和基类之间的类型转换 首先理解,派生类含有基类的所有成分,只不过有些就算在派生类的成员函数也不能访问而已。
(1)派生类和基类的自动转换只针对指针或引用类型。 只有指针和引用支持自动类型转换,同时,也只有指针和引用才可以静态类型和动态类型不同,这两个配合就完成了c++的最重要的多态。
派生类到基类的自动类型转换也不是都能随便转换的。
1.如果派生类以public继承基类,则是is a关系,用派生类可以完成基类的所有功能,所以可以在任意地方将派生类自动转换成基类,注意,这里都是指指针或引用,而不是对象。 比如:
class A{};
class B:public A{}
B b;
void function(const A &);
这时就可以使用function(b),会默认把B类型转换成A类型。
2.假定D继承B:
不论D以什么方式继承B,D的成员函数和友员函数都能使用派生类向基类的转换;派生类向其直接基类的类型转换对于派生类的成员函数和友员函数来说永远是可访问的。
例如:
class B{}
class D:private B //这里以private或者protected或者public 都可以
{
void f()
{
B * base=new D; //编译正确
}
}
如果不是成员函数(即用户代码),例如:
class B{};
class D:private B //如果这里是public就可以,private或protected会错
{
/*void f()
{
B * base=new D;
}
*/
};
int main()
{
B * b=new D; //会出现编译错误,注意,这是用户代码
};
3.如果D继承B的方式是public或者protected,则D的派生类的成员或者友员可以使用D向B的类型转换;反之,如果D继承B的方式是private,则不能使用。
class B{};
class D:public B{};//public或protected都可以
class E:private D或者protected D或者public D
{
void f()
{
B *b=new D; //可以编译通过
D *d=new E; //可以编译通过,这就是2介绍的情况。
}
};
但是如果变成private继承:
class B{};
class D:private B{};
class E:private D或者protected D或者public D
{
void f()
{
B *b=new D; //错,不可以编译
D *d=new E; //可以编译,这就上2介绍的情况
}
};
4.附加下别人做的实验,所以实验均亲身验证,c++ primer真心厉害!
- //p489 派生类到基类转换的可访问性
- #include<iostream>
- using namespace std;
- class A{};
- class B:public A{};
- class C:protected A{};
- class D:private A{};
- class E:public B{};
- class F:public C{};
- class G:public D{};
- int main(){
- A *pb, *pc, *pd, *pe, *pf, *pg;
- pb = new B; // 正确 public派生,可以转换[*B ---> *A].
- pc = new C; // 错误 protected派生,不可转换[*C -\-> *A].
- pd = new D; // 错误 private派生,不可转换[*D -\-> *A].
- pe = new E; // 正确 public派生的子类,可以转换[*E ---> *A].
- pf = new F; // 错误
- pg = new G; // 错误 private派生的子类,不可转换[*G -\-> *A].
- return 0;
- }
用户代码是除成员函数、友元之外的代码。
(2)不存在从基类到派生类的隐式类型转换,注意是隐式。这里也指的指针和引用
因为如果开始时就是基类的类型,就根本不存在派生类的部分,所以转换肯定错。但是如果是基类的对象是派生类的一部分,指针指向的是基类对象,那就可以通过强制类型转换,如static_cast 或dynamic_cast转换成。
例如:
Quote base;
Bulk_quote * bulkp=&base; 错,不能将基类转换成派生类
即使一个基类指针或引用绑定在一个派生类对象上,我们也不能执行从基类到派生类转换:
Bulk_quote bulk;
Quote * itemP=&bulk; //正确动态类型是Bulk_quote
Bulk_quote * bulkp=itemP //错误,不能将基类转换成派生类,因为itemP的静态类型是Quote,虽然动态类型已经变成了Bulk_quote。因为编译器是根据静态类型推断转换是否合法。但可以通过强制类型转换
Bulk_quote * bulkp = static_cast<Bulk_quote> itemp;
或者Bulk_quote * buklp=dynamic_cast<Bulk_quote>itemp;
通过强制类型转换,覆盖掉编译器检查。
(3)在对象之间不存在类型转换。
对象之间不存在类型转换。
例如:
Bulk_quote bulk; //派生类对象
Quote item(bulk); // 这时会使用Quote::Quote(const Quote &)构造函数,我感觉这里也用到了派生类到基类的转换,这里有引用,如果要是用private继承是否就不行呢?回头试,果然如我所料,如果是以public继承,是可以将Bulk_quote转换成Quote的,可以编译通过,如果改成以private继承或者以protected继承,根本编译不过。如果用static_cast<Quote>强制类型转换也是不可以的,因为以private或protected继承,就不能从派生类转换成基类
item=bulk; //调用Quote::operator=(const Quote &),同上。
就算是成功进行拷贝,这里会切割忽略Bulk_quote部分,值复制Bulk_quote中的Quote对象部分。
c++ 派生类向基类转换的可访问性的更多相关文章
- 从零开始学C++之继承(二):继承与构造函数、派生类到基类的转换
一.不能自动继承的成员函数 构造函数 析构函数 =运算符 二.继承与构造函数 基类的构造函数不被继承,派生类中需要声明自己的构造函数. 声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类 ...
- C++ 派生类到基类转换的可访问性
今天看c++ primer关于派生类到基类转换的可访问性,看的很晕,看了下面的文章恍然大悟: http://www.2cto.com/kf/201403/283389.html C++ primer第 ...
- c++ primer 学习杂记2【派生类到基类转换的可访问性】
参考: http://blog.csdn.net/rehongchen/article/details/7930853 http://blog.csdn.net/ming_road/article/d ...
- c++——派生类和基类转换(类型兼容性原则)
基类也叫父类,派生类也叫子类. 类之间的继承关系继承关系是类之间的父子关系. 继承关系的特点如下:A. 子类拥有父类的所有属性和行为B. 子类也是一种特殊的父类C. 子类对象可以当父类对象使用D. 子 ...
- C#中派生类调用基类构造函数用法分析
这里的默认构造函数是指在没有编写构造函数的情况下系统默认的无参构造函数 1.当基类中没有自己编写构造函数时,派生类默认的调用基类的默认构造函数例如: ? 1 2 3 4 5 6 7 8 9 10 11 ...
- 转 关于C#中派生类调用基类构造函数的理解
关于C#中派生类调用基类构造函数的理解 .c#class 本文中的默认构造函数是指在没有编写构造函数的情况下系统默认的无参构造函数 1. 当基类中没有自己编写构造函数时,派生类默认的调用 ...
- c++中派生类对基类成员的三种访问规则(转)
C++中派生类对基类成员的访问形式主要有以下两种:1.内部访问:由派生类中新增成员对基类继承来的成员的访问.2.对象访问:在派生类外部,通过派生类的对象对从基类继承来的成员的访问.今天给大家介绍在3中 ...
- C++_派生类的构造函数及派生类和基类之间的特殊关系
派生类和基类的概念及派生类构造函数的原理: 创建一个叫做TableTennisPlayer的基类,记录会员的名字和是否有球桌. //声明一个基类 class TableTennisPlayer { p ...
- C# 派生和继承(派生类与基类)
using System; using System.Collections.Generic; using System.Text; namespace 继承 { class Program { st ...
随机推荐
- linux shell命令的常用快捷键
一些shell的常用快捷键. Ctrl + a 切换到命令行开始 Ctrl + e 切换到命令行末尾 Ctrl + l 清除屏幕内容 Ctrl + u 清除剪切光标之前的内容 Ctrl + ...
- php curl request
/** * @desc curl request请求 * @date 2016-12-07 16:26:55 * * @param $arguments * * @return bool|mixed ...
- Django操作数据库
引入models的定义 from app.models import myclass class myclass(): aa = models. CharField (max_leng ...
- 从Python传递JSON到JavaScript
OS: Windows 8.1 with update 关键字:Python 3.4,HTML5,JSON,JavaScript 1.LocalServer.py,启动server,打开网页,传递JS ...
- 【DB】SQLiteHelper
/// <summary> /// 说明:这是一个针对System.Data.SQLite的数据库常规操作封装的通用类. /// </summary> public class ...
- Java学习-Overload和Override的区别
1.Overload是重载的意思,Override是覆盖的意思,也就是重写. 2.重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同). 3 ...
- 模拟DLL加载
#include <stdio.h> #include <malloc.h> #include <sys/stat.h> typedef int (*PFUNC)( ...
- jna 使用实例,
有与项目组需要用到C++的一个模块, 需要将一个2维数组传到dll 里面 ,返回一个字符串, 恶心了1天终于完成了, 记录一下,同时也希望能给你带来帮助. java 代码如下, package tes ...
- BZOJ 3901 棋盘游戏 解题报告
这题有个重要性质: 我们设 Flag[i][j] 表示 (i, j) 是否被奇数个操作所覆盖, 也就是操作次数对 2 取模. 设 x = (n + 1) / 2. 那么对于所有的合法的操作方案, 令 ...
- BT5升级MSF至Git更新的方法
由于Kali在虚拟机的运行效率实在让人不敢恭维,于是决心将BT5中的MSF进行升级,升级的主要目的是,BT5R3内置的MSF是用SVN进行更新, 但是新版本的MSF已经停止通过SVN更新,改用Git, ...