对于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. apache开启gzip的方法

    在Apache中开启gzip压缩方法为: 1. 在httpd.conf 或者博客根目录的.htaccess文件中加入如下规则(Apache服务器需要支持 mod_deflate) 本文出处参考:htt ...

  2. CentOS安装mplayer

    据说mplayer相当于windows下的暴风影音,那么今天就来安装上mplayer. 安装的大体步骤: 安装mplayer需要安装,解码器,mplayer,皮肤. 这三个包你都可以在mplayer官 ...

  3. 【python】坑,坑,折腾一个下午python 3.5中 ImportError: No module named BeautifulSoup

    将语句 from bs4 import BeautifulSoup4 改成 from bs4 import BeautifulSoup 通过 尼玛------------------------! 总 ...

  4. R语言和大数据

    #安装R语言R3.3版本会出现各种so不存在的问题,退回去到R3.1版本时候就顺利安装.在安装R环境之前,先安装好中文(如果没有的话图表中显示汉字成框框了)和tcl/tk包(少了这个没法安装sqldf ...

  5. shell中的重定向(2>&1)

    shell的输出可以分为标准输出和错误输出,2>&1中,2代表错误输出,1代表标准输出,&符号代表后面跟的是代号而不是文件. test.sh echo '我是标准输出' ls / ...

  6. boost linux 下安装

    1. 在boost 官网 http://www.boost.org/doc/libs/ 下载最新的boost 安装包 2. 解压至 /usr/local/ 目录下 3. cd /usr/local/b ...

  7. 常用后台frame框架

    一般后台框架结构: top:左边显示logo,右边显示模块信息. left:对应模块的菜单信息. content:具体的内容. bottom:版权.时间等一些碎屑信息. Html代码: <htm ...

  8. BZOJ 1507 [NOI2003]Editor

    Description Input 输 入文件editor.in的第一行是指令条数t,以下是需要执行的t个操作.其中: 为了使输入文件便于阅读,Insert操作的字符串中可能会插入一些回车符,请忽略掉 ...

  9. JAVA入门第二季(mooc-笔记)

    相关信息 /** * @subject <学习与创业>作业1 * @author 信管1142班 201411671210 赖俊杰 * @className <JAVA入门第二季&g ...

  10. php调用whois接口域名查询

    由两部分组成,一个index.php文件,一个whois的接口文件: <html> <head> <title>域名到期查询</title> <s ...