对于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. 【pyhton】【转】修改递归次数

    import sys sys.setrecursionlimit(1500) # set the maximum depth as 1500 def recursion(n): if(n <= ...

  2. TypeScript学习指南第一章--基础数据类型(Basic Types)

    基础数据类型(Basic Types) 为了搭建应用程序,我们需要使用一些基础数据类型比如:numbers,strings,structures,boolean等等. 在TypeScript中除了Ja ...

  3. vi 在行首尾添加字符串

    在行首尾添加字符串     用下列命令在文本每行的行首添加字符串“NewString”,请注意空格的存在.      :g/^/s//NewString/g     :%s/^/NewString/g ...

  4. Python和VS

    下载VS Code 安装插件Python 安装Python,注意这里需要把Python的目录配置到环境变量中 文档结构非常重要,py文件一定位于根目录,.vscode平级:我曾经因为py文件在.vsc ...

  5. MongoDB索引介绍

    MongoDB中的索引其实类似于关系型数据库,都是为了提高查询和排序的效率的,并且实现原理也基本一致.由于集合中的键(字段)可以是普通数据类型,也可以是子文档.MongoDB可以在各种类型的键上创建索 ...

  6. 用 Maven 做项目构建

    转自:http://www.ibm.com/developerworks/cn/java/j-lo-maven/index.html 本文将介绍基于 Apache Maven 3 的项目构建的基本概念 ...

  7. PHP unlink() 函数

    定义和用法 unlink() 函数删除文件. 若成功,则返回 true,失败则返回 false. 语法 unlink(filename,context) 参数 描述 filename 必需.规定要删除 ...

  8. SQL跨表更新

    [一篮饭特稀原创,转载请注明出自http://www.cnblogs.com/wanghafan/p/4384039.html]  前提:两张表要更新的字段.关联字段结构一致 更新库:FJPDI_TZ ...

  9. GridView 根据要求显示指定值

    最近在写一个小项目用来练手恢复一下功力的,在Users表中有一个用户字段是状态,我使用"0"表示启用,“1”表示禁用, 存到数据库中, 由于之前有一段时间没写代码了,所以有点生疏了 ...

  10. 综合经验:IO读写错误必然导致程序崩溃

    仿佛是忽然间产生的问题,每次程序退出时候,必然崩溃,花了整整一天才找到原因,就是对数据库的IO读写错误.主要是因为析构函数调用了Disconnect函数,内容如下: void SFTPTool::Di ...