对于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真心厉害!

    1. //p489 派生类到基类转换的可访问性
    2. #include<iostream>
    3. using namespace std;
    4. class A{};
    5. class B:public A{};
    6. class C:protected A{};
    7. class D:private A{};
    8. class E:public B{};
    9. class F:public C{};
    10. class G:public D{};
    11. int main(){
    12. A *pb, *pc, *pd, *pe, *pf, *pg;
    13. pb = new B;     // 正确 public派生,可以转换[*B ---> *A].
    14. pc = new C;     // 错误 protected派生,不可转换[*C -\-> *A].
    15. pd = new D;     // 错误 private派生,不可转换[*D -\-> *A].
    16. pe = new E;     // 正确 public派生的子类,可以转换[*E ---> *A].
    17. pf = new F;     // 错误
    18. pg = new G;     // 错误 private派生的子类,不可转换[*G -\-> *A].
    19. return 0;
    20. }

用户代码是除成员函数、友元之外的代码。

(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++ 派生类向基类转换的可访问性的更多相关文章

  1. 从零开始学C++之继承(二):继承与构造函数、派生类到基类的转换

    一.不能自动继承的成员函数 构造函数 析构函数 =运算符 二.继承与构造函数 基类的构造函数不被继承,派生类中需要声明自己的构造函数. 声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类 ...

  2. C++ 派生类到基类转换的可访问性

    今天看c++ primer关于派生类到基类转换的可访问性,看的很晕,看了下面的文章恍然大悟: http://www.2cto.com/kf/201403/283389.html C++ primer第 ...

  3. c++ primer 学习杂记2【派生类到基类转换的可访问性】

    参考: http://blog.csdn.net/rehongchen/article/details/7930853 http://blog.csdn.net/ming_road/article/d ...

  4. c++——派生类和基类转换(类型兼容性原则)

    基类也叫父类,派生类也叫子类. 类之间的继承关系继承关系是类之间的父子关系. 继承关系的特点如下:A. 子类拥有父类的所有属性和行为B. 子类也是一种特殊的父类C. 子类对象可以当父类对象使用D. 子 ...

  5. C#中派生类调用基类构造函数用法分析

    这里的默认构造函数是指在没有编写构造函数的情况下系统默认的无参构造函数 1.当基类中没有自己编写构造函数时,派生类默认的调用基类的默认构造函数例如: ? 1 2 3 4 5 6 7 8 9 10 11 ...

  6. 转 关于C#中派生类调用基类构造函数的理解

    关于C#中派生类调用基类构造函数的理解 .c#class       本文中的默认构造函数是指在没有编写构造函数的情况下系统默认的无参构造函数 1.  当基类中没有自己编写构造函数时,派生类默认的调用 ...

  7. c++中派生类对基类成员的三种访问规则(转)

    C++中派生类对基类成员的访问形式主要有以下两种:1.内部访问:由派生类中新增成员对基类继承来的成员的访问.2.对象访问:在派生类外部,通过派生类的对象对从基类继承来的成员的访问.今天给大家介绍在3中 ...

  8. C++_派生类的构造函数及派生类和基类之间的特殊关系

    派生类和基类的概念及派生类构造函数的原理: 创建一个叫做TableTennisPlayer的基类,记录会员的名字和是否有球桌. //声明一个基类 class TableTennisPlayer { p ...

  9. C# 派生和继承(派生类与基类)

    using System; using System.Collections.Generic; using System.Text; namespace 继承 { class Program { st ...

随机推荐

  1. DELPHI 取文件名和扩展名

    x:=ExtractFileName(str);  //取文件名+扩展名,不包含文件路径 y:=ExtractFileExt(str);   //取文件的扩展名

  2. WPF中三种方法得到当前屏幕的宽和高

    WPF程序中的单位是与设备无关的单位,每个单位是1/96英寸,如果电脑的DPI设置为96(每个英寸96个像素),那么此时每个WPF单位对应一个像素,不过如果电脑的DPI设备为120(每个英寸120个像 ...

  3. javascript高级编程笔记03(正则表达式)

    引用类型 检测数组 注:我们实际开发中经常遇到要把数组转化成以逗号隔开,我以前都是join来实现,其实又更简单的方法可以用toString方法,它会自动用逗号隔开转换成字符串,其实toString内部 ...

  4. Javascript 5种方法实现过滤删除前后所有空格

    第一种:循环检查替换 //供使用者调用 function trim(s){ return trimRight(trimLeft(s)); } //去掉左边的空白 function trimLeft(s ...

  5. 视频边下边播--缓存播放数据流-b

    google搜索“iOS视频变下边播”,有好几篇博客写到了实现方法,其实只有一篇,其他都是copy的,不过他们都是使用的本地代理服务器的方式. 原理很简单,但是缺点也很明显,需要自己写一个本地代理服务 ...

  6. Android Learning:微信第三方登录

    这两天,解决了微信第三方授权登录的问题,作为一个新手,想想也是一把辛酸泪.我想着,就把我的遇到的坑给大家分享一下,避免新手遇到我这样的问题能够顺利避开. 步骤一 微信开发者平台 我开始的解决思路是,去 ...

  7. Tesseract 3 语言数据的训练方法

    OCR,光学字符识别 光学字符识别(OCR,Optical Character Recognition)是指对文本资料进行扫描,然后对图像文件进行分析处理,获取文字及版面信息的过程.OCR技术非常专业 ...

  8. 1010 [HNOI2008]玩具装箱toy

    斜率优化dp: 推荐学习http://www.cnblogs.com/perseawe/archive/2012/05/12/bz1010.html 看着别人的题解自己学着推,终于理解了 #inclu ...

  9. Moloch

    http://www.oschina.net/p/moloch maltego http://www.oschina.net/p/maltego

  10. ASP.NET MVC 入门3、Routing

    本系列文章基于Microsoft ASP.NET MVC Beta. 在一个route中,通过在大括号中放一个占位符来定义( { and } ).当解析URL的时候,符号"/"和& ...