派生类到基类转换的可访问性——新解
来源:互联网 发布:知乎的缺点 编辑:程序博客网 时间:2024/06/05 09:01
C++ primer第四版15.3小节有这样一段话:
如果是 public 继承,则用户代码和后代类都可以使用派生类到基类的转换。
如果类是使用 private 或 protected 继承派生的,则用户代码不能将派生类型对象转换为基类对象。
首先明白:什么是可访问,个人觉得可访问就是可出现。A可以访问B,就说名B可以直接在A中出现。
派生类到基类的转换包括:派生类对象的引用转换为基类对象的引用;派生类对象的指针转换为基类对象的指针;派生类对象转换为基类对象。
//Base.h#ifndef _BASE_H_#define _BASE_H_#include <IOSTREAM>using namespace std;class CBase{public:CBase();
virtual ~CBase(){};CBase(const CBase & b);virtual void vir_display() const;void Novir_display()const;private:int val;};#endif //_BASE_H_
//Base.cpp#include "Base.h"void CBase::Novir_display() const{cout << "调用CBase的非虚函数" << endl;}void CBase::vir_display() const{cout << "调用CBase的虚函数" << endl;}CBase::CBase(){val =0;}CBase::CBase(const CBase & b ){val = b.val;}<pre class="cpp" name="code">//Derived.h#ifndef _DERIVED_H_#define _DERIVED_H_#include "Base.h"class CDrived : public CBase{public:CDrived();CDrived(const CDrived & d);public:void Novir_display() const;void vir_display() const;private:double data1;double data2;};#endif //_DERIVED_H_
//Derived.cpp#include "Derived.h"void CDrived::Novir_display() const{cout << "调用CDrived的非虚函数" << endl;}void CDrived::vir_display() const{cout << "调用CDrived的虚函数" << endl;}CDrived::CDrived(){}CDrived::CDrived( const CDrived & d ){data1 = d.data1;data2 = d.data2;}
//show_main.cpp#include "Base.h"#include "Derived.h"void show_Obj(const CBase b){b.Novir_display();b.vir_display();}void show_Ptr(const CBase& b){b.Novir_display();b.vir_display();}int main(){CDrived d;show_Obj(d);show_Ptr(d);return 0;}
实验结果:
调用CBase的非虚函数调用CBase的虚函数调用CBase的非虚函数调用CDrived的虚函数请按任意键继续. . .
解析:
CDrived 继承CBase的方式为public,故上面可以执行。如果,继承方式换成protected,则出现error:“类型转换”: 从“CDrived *”到“const CBase &”的转换存在,但无法访问。因为在show_main.cpp中,CDrived对象转换为CBase对象时需要调用CBase的复制构造函数,而此时CBase的构造函数都变成了protected,在用户代码中无法访问。
对于show_Ptr(d)也出现这个错误,但不是由于调用CBase的复制构造函数产生的,如果声明为void show_Prt(CBase&),则错误为:从“CDrived *”到“CBase &”的转换存在,但无法访问。可见error中的const也跟着消失了。为何会出现这个错误呢?目前没搞懂,求高人赐教。
个人理解:对于private或protected继承,派生类对象中的基类对象部分已经变成private或protected的,故无法在用户代码中访问。
再在Derived.h中添加三个函数来制造派生类对象到基类对象的转换,此时CDrived是protected继承方式
void CDrived::dis_Ref(const CBase& b ){b.vir_display();b.Novir_display();}void CDrived::dis_Obj(const CBase b ){b.vir_display();b.Novir_display();}void CDrived::test_CDrived(){//在子类中访问子类转换为基类类型CDrived d;dis_Ref(d);dis_Obj(d);}
//show_main.cpp
int main(){CDrived d; d.test_CDrived();return 0;}
调用CDrived的虚函数
调用CBase的非虚函数
调用CBase的虚函数
调用CBase的非虚函数
可见,protected继承时转换是在派生类中可访问的,即protected继承时,在派生类中派生类到基类的转换是可访问的,在用户代码是不可访问的。
二、如果是 private 继承,则从 private 继承类派生的类不能转换为基类。
先看部分三,然后修改为class CDrived :protected CBase即可,其他不变。结果出现上面的类型转换错误。
三、如果是 protected 继承,则后续派生类的可以访问后续派生类转换为基类类型。
定义class CNext : public CDrived,此时class CDrived :protected CBase。
//Next.h
#ifndef _NEXT_H_#define _NEXT_H_#include "Derived.h"class CNext : public CDrived{public: void Novir_display();void dis_Ref(const CBase& b);void dis_Obj(const CBase b);void test_CNext();virtual void vir_display() const;};#endif //
//Next.cpp
#include "Next.h"void CNext::Novir_display(){cout << "调用子类的子类的非虚函数" <<endl;}void CNext::dis_Ref(const CBase& b ){b.vir_display();b.Novir_display();}void CNext::dis_Obj( const CBase b ){b.vir_display();b.Novir_display();}void CNext::test_CNext(){//在子类的子类中访问子类的子类转换为基类类型CNext cn;dis_Ref(cn);dis_Obj(cn);}void CNext::vir_display() const{cout << "调用CNext的虚函数" << endl;}
//show_main.cpp
#include "Base.h"#include "Derived.h"#include "Next.h"int main(){CDrived d; d.test_CDrived();CNext cn;cn.test_CNext();// CBase *pb = new CNext; //failed//CDrived * pd = new CNext; //failedreturn 0;}
实验结果:
调用CDrived的虚函数
调用CBase的非虚函数
调用CBase的虚函数
调用CBase的非虚函数
调用CNext的虚函数
调用CBase的非虚函数
调用CBase的虚函数
调用CBase的非虚函数
可见,在子类的子类CNext中,CNext类型可以转换为基类型CBase。
- 派生类到基类转换的可访问性——新解
- 派生类到基类转换的可访问性
- 派生类到基类转换的可访问性
- 派生类到基类转换到可访问性
- 《C++ Primer》派生类到基类转换的可访问性
- c++ 初学 派生类到基类转换的可访问性
- C++ 派生类到基类转换的可访问性
- C++ 派生类到基类转换的可访问性(是否可以转换)
- 派生类转换到基类的可访问性
- 派生类向基类转换的可访问性
- 派生类向基类转换的可访问性
- C++笔记:派生类到基类转换到可访问性
- 派生类向基类类型转换的可访问性
- c++派生类向基类转换的可访问性
- C++ 学习(派生类到基类准还的可访问性)
- 派生类到基类的转换
- 派生类到基类的转换
- 派生类到基类的转换 和基类到派生类的转换
- POJ 1988 Cube Stacking(并查集)
- http://travel.tianya.cn/travelPlan/showPlan?planId=958409
- Spring接口ApplicationContextAware介绍及使用
- CF#254 (Div. 2) B.
- 三种对象初始化代码,有何不同求解答
- 派生类到基类转换的可访问性——新解
- 60 谁获得了最高奖学金
- HDU4870:Rating(DP)
- mysql数据库迁移
- Code Jam - Store Credit for Python
- VPN寻址及路由
- struts2 全局拦截器,显示请求方法和参数
- 62 笨小熊
- 字典树模板及讲解 http://www.cnblogs.com/tanky_woo/archive/2010/09/24/1833717.html