一、类的继承与类型转换

1.概述

一般情况,如果想把一个类的指针或引用绑定到另外一个对象上,需要指针或者引用的类型与指向对象一致。但是存在继承关系的类是个例外:可以将基类的指针或者引用指向子类

原因是因为:子类包含了父类非static成员和它本身的非static成员。因此,当一个基类的指针或引用指向子类对象时,所指向的真实对象有可能仅仅是父类,也有可能是完整的子类

上图中,指针或引用的类型叫静态类型,指针或引用指向的对象叫动态类型。静态类型在编译期就已经确定,而动态类型是不确定的(有可能是父类对象,也有可能是完整的子类),所以只能在运行时才能确定

当然,如果不适用指针或者引用,那么动态类型和静态类型永远一致,都是类名。

2.父子类的类型转换

正因为基类对象是完整的子类对象的一部分,而基类的指针或引用可以指向子类中基类的部分,所以,子类可以转化为基类,但是基类不能转化为子类,子类可以当做基类使用,而基类却不能当做子类使用。再简言之就是子类的中的成员基类没有,而基类的成员子类都有,所以基类不能转子类,子类能转基类

示例

class base1
{
public:base1(){}~base1(){}static void sfunc() {cout<<__func__<<endl;}static int st;
};int base1::st=10;class derive2:public base1
{
public:derive2(){cout<<__func__<<endl;}~derive2(){cout<<__func__<<endl;}
};int main(int argc, char const *argv[])
{derive2 d2;base1 b1=d2;base1 b1t;b1t=d2;derive2 t=b1;return 0;
}

基类在给子类初始化时,需要转化为子类,又因为基类不能转子类,所以报错

无论是用子类对象给基类对象赋值,还是用子类对象给基类对象初始化,调用的都是基类的拷贝构造或者基类的operator=,而拷贝构造和operator=的形参是const 对象的引用,而基类的引用可以指向子类对象,所以可以将子类对象作为实参,而在基类的拷贝构造或者operator=中,只能对基类中的成员进行初始化或者赋值,无法处理子类中的成员,所以当使用子类对象对基类对象进行初始化时,除基类外的子类部分被切掉了简言之就是基类中没有子类的成员,所以除基类外的子类部分被切掉了

此外,子类的指针或引用也不能指向基类。即使一个基类的指针或引用绑定在子类上,也不能让子类的指针或引用指向基类

示例1

int main(int argc, char const *argv[])
{base1 b1;derive2 *p=&b1;return 0;
}

如果子类的指针可以指向基类,那么就可以通过子类的指针访问基类中原来没有的成员,所以,不允许子类的指针或引用指向基类对象

示例2

int main(int argc, char const *argv[])
{base1 *pb=new derive2();derive2 *p=pb;return 0;
}

虽然基类的指针指向了一个子类,并且子类指针也指向了该子类对象,但是编译器在编译derive2 *p=pb;时发现:有子类的指针指向基类,于是编译器认为违反了子类的指针或引用不能指向基类的原则,所以报错

总之,不能用子类的指针或者引用指向基类

二、protected关键字的其他性质

protected是专为继承而生的,基类中的protected成员对于除子类的其他类和作用域来说是不可访问的;对于子类的成员和友元是可以访问的

注意:在子类中访问父类的protected成员时,只能通过子类对象访问,不能通过父类对象访问

示例

class base3
{
public:base3(){cout<<__func__<<endl;}~base3(){cout<<__func__<<endl;}
protected:int i;
};class derive3:public base3
{
public:derive3(){cout<<__func__<<endl;}~derive3(){cout<<__func__<<endl;}//void func(base3 &b) {b.i=3;} //需要注释掉void func2(derive3 &d) {d.i=3;}
};

上述代码的第15行如果不注释掉,会报错,因为在子类中访问父类的protected成员时,只能通过子类对象访问,不能通过父类对象访问

三、类的继承与友元

如果一个类的可以做基类,那么,当该类被继承时,基类中的友元不会被继承,不能成为子类的友元,所以基类的友元不能访问子类对象的成员。同样,子类中的友元也不能访问基类中的protected和private成员。简言之,子类和基类中的友元没有任何关系

示例

class base4
{friend class friendclass;
public:base4(){cout<<__func__<<endl;}~base4(){cout<<__func__<<endl;}protected:int i1;private:int i2;
};class derive4:public base4
{
friend void setfunc(derive4 &b);
friend void setfunc(base4 &b);
public:derive4(){cout<<__func__<<endl;}~derive4(){cout<<__func__<<endl;}protected:int i3;private:int i4;
};class friendclass {
public:friendclass() {cout<<__func__<<endl;}~friendclass() {cout<<__func__<<endl;}void set(derive4 &d) {d.i1=10;d.i2=10;d.i3=10;d.i4=10;}
};void setfunc(derive4 &d) {d.i1=10;d.i2=10;d.i3=10;d.i4=10;
}void setfunc(base4 &d) {d.i1=10;d.i2=10;
}

上述代码有编译无法通过的原因:

1、friendclass是base4的友元而不是derive的友元,所以friendclass中的set函数无法访问子类derive中的成员(i3, i4)

2、void setfunc(derive4 &b);是子类的友元,但是不是基类的友元,所以无法访问基类中的private成员(i2)。但是由于derive4是base4的子类,所以可以通过子类访问基类中的protected成员i1

3、friend void setfunc(base4 &b);虽然是子类derive的友元,但是参数是基类base4的引用,所以无法在子类中通过基类base4访问基类的protected成员i1,更无法访问基类的private成员i2

参考

《C++ Primer》

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

C++知识点45——类继承中的类型转换与访问权限控制(上)相关推荐

  1. C++知识点47——类继承中的类型转换与访问权限控制(下)

    接上一篇文章https://blog.csdn.net/Master_Cui/article/details/109768311 五.派生类向基类转换的可访问性 当一个子类向基类转化时:有以下三条规则 ...

  2. C++知识点46——类继承中的类型转换与访问权限控制(中)

    接上一篇文章https://blog.csdn.net/Master_Cui/article/details/109741735 四.public继承.protected继承和private继承 子类 ...

  3. android 静态方法 构造方法,android基础-Java篇02:类和对象、构造方法、访问权限控制、重载、this关键字、static关键字...

    一.类和构造方法 (类和对象在百度百科已经有详细的介绍,这里只做简单的描述以及帮助理解:百度百科:类和对象,需要注意的是,百度百科类和对象的举例中都是C++,书写格式不要和Java混淆!) 什么是类? ...

  4. C# 类型运算符重载在类继承中的调用测试

    C# 类型运算符重载在类继承中的调用测试 这是一篇晦涩难懂的片面的研究 一,简单的继承层次 class CA {}class CB : CA{}class CC : CB{}}void Test(CA ...

  5. C++_类和对象_封装_访问权限_C++中struct和class的区别---C++语言工作笔记037

    然后我们再来看c++中的访问权限控制,其实这个跟java中的很像 可以看到有3个,public 是类内类外都可以访问 protected 是保护权限,在类内可以访问,但是在类外不行.  这个在子类的时 ...

  6. Java中的四种访问权限:public、protected、包访问、private

    所谓访问权限,指的就是本类中的成员变量.成员方法对其他类的可见性 试想一想,当我们修改一个非常庞大的项目时,如果所有变量和方法都是公共权限,那么后端中任何类都有权限去修改它的变量和方法,很有可能修改后 ...

  7. C++知识点11——this指针,const成员函数,访问权限控制

    1.this指针 每个类都有this指针,this指针指向this指针指向的是类的对象本身 class A { public:A() {}~A() {}void func() {cout<< ...

  8. private访问权限java_Java中的访问权限控制

    Java提供了public, private, protected 三个访问权限修饰词,提供了以下四种访问权限控制机制: 1.包访问权限: 2.Public访问权限: 3.Private访问权限: 4 ...

  9. 文件服务器共享文件夹访问权限,5对文件服务器中的共享文件夹进行访问权限控制...

    对文件服务器中的共享文件夹进行访问权限控制 1. 实训目的 在Windows Server 2003环境下设置文件服务器的目的是要对多用户进行资源共享,这其中经常遇到不同用户应该分配不同权限的问题,通 ...

最新文章

  1. 启动 Tensorboard
  2. java储存学生档案应该注意事项_档案管理的注意事项有哪些
  3. python 单元测试 unittest
  4. centos 6.5 配置网络
  5. 公开课 | 知识图谱构建与应用概述
  6. 输入网址后发生了什么
  7. Java通过JNI调用C++的DLL库
  8. 傻瓜攻略(十九)——MATLAB实现SVM多分类
  9. Flask-SQLAlchemy relationship中的 lazy屬性
  10. 网站服务器无法打开ie,internet explorer无法打开站点怎么办
  11. 股份有限公司按规定注销库存股时,对被注销库存股的账面余额超过面值总额的部分
  12. pip 切换清华镜像源
  13. A-Level经济真题(7)
  14. 文字识别(四)--大批量生成文字训练集
  15. viewsets.ModelViewSet
  16. Bebras挑战样题之四——小海狸的密码机器
  17. 一键生成所有接口的文档 Swagger + springBoot
  18. 跨域 万金油解决方法 非原理向
  19. 剑指offter Java单链表反转
  20. 科创人·SUSE大中华区董事长江永清:真开源要有打磨技术的匠心,要能持续创造社会价值

热门文章

  1. 深耕大数据“试验田” 发掘新经济“钻石矿”
  2. PHP date函数参数详解
  3. Lamp(fastcgi)环境的搭建
  4. VS2010 ASP.NET MVC4 安装失败问题
  5. matlab生成wav文件并用python验证
  6. 基于Springboot实现宠物医院综合管理系统
  7. C++ string流
  8. mkdir创建递归目录
  9. Linux PuTTY 更改字体
  10. 终止线程的2种方法。标记法和中断