对于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. javascript学习笔记3

    一 判断下列数值中哪些于false相等? 0, 0.0, 0.000, -0, -0.0, 000, "0",  "0.0", "0.000" ...

  2. 【Ubuntu12.04】安装搜狗输入法

    我的系统版本是Ubuntu12.04 32位 卸载Ibus输入法 sudo apt-get remove ibus 注意: 安装ibus的命令是  sudo apt-get install fcitx ...

  3. 【Django】基于Django架构网站代码的目录结构

     经典的Django项目源码目录结构 Django在一个项目的目录结构划分方面缺乏必要的规范.在Django的官方文档中并没有给出大型项目的代码建议目录结构,网上的文章也是根据项目的不同结构也有适当的 ...

  4. Fluid Shopping Website 开发阶段性总结——第一周

    开发目的: 可链接微信公众号,无论是桌面端.移动端完美兼容,给用户提供不逊于原生App的用户体验.作为一个软件,有充分的可扩展性,便于未来增强开发.同时给一些正在尝试做OTO的朋友们提供一个平台,因为 ...

  5. codeforces Codeforces Round #345 (Div. 1) C. Table Compression 排序+并查集

    C. Table Compression Little Petya is now fond of data compression algorithms. He has already studied ...

  6. codeforces 630K - Indivisibility

    K. Indivisibility 题意:给一个n(1 <= n <= 10^18)的区间,问区间中有多少个数不能被2~10这些数整除: 整除只需要看素数即可,只有2,3,5,7四个素数: ...

  7. NSCharacterset

    我们在nsstring的分割,查找等操作中,经常会提供两种函数,参数类型分别为NSString 和NSCharacterset,有什么不同呢? NSString 是有序字符串 NSCharacters ...

  8. JS 操作URL(重要)

    我们可以用javascript获得其中的各个部分1, window.location.href全部URl字符串(在浏览器中就是完整的地址栏)本例返回值: http://www.x2y2.com:80/ ...

  9. leetcode-173:Binary Search Tree Iterator(Java)

    Binary Search Tree Iterator Implement an iterator over a binary search tree (BST). Your iterator wil ...

  10. csuoj 1352: New Sorting Algorithm

    因为每个元素都是移动到比它小1位的元素的后面: 这样的话以后的一定就可以把他们两个打包: 所以用这种方法最多扫一遍就可以了: 但是最小的那个数要不要移动呢? 如果最小的数后面的数都是升序的,那么一直扫 ...