博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
继续(三)
阅读量:4561 次
发布时间:2019-06-08

本文共 4416 字,大约阅读时间需要 14 分钟。

 派生类对象也是基类对象。这意味着在使用基类的地方可以用派生类来替换。

  • 当派生类以public方式继承基类时,编译器可自动执行的转换(向上转型 upcasting 安全转换)
    ①、派生类对象指针自动转化为基类对象指针。

    下面用代码进行说明:

    #include 
    #include
    using namespace std;class Employee {//员工类public: Employee(const string& name, const int age, const int deptno) : name_(name), age_(age), deptno_(deptno) { }private: string name_; int age_; int deptno_; }; class Manager : public Employee {//经理类 public: Manager(const string& name, const int age, const int deptno, const int level) : Employee(name, age, deptno), level_(level) { } private: int level_; }; int main(void) { Employee e1("zhangsan", 25, 20); Manager m1("lisi", 35, 20, 10); Employee* pe; Manager* pm; pe = &e1;//基类指针指向派生类对象 pm = &m1;//派生类指针指向派生类对象 return 0; }

    以上代码都可正常编译:

    编译是可正常通过的,那如果反过来,将派生类指针指向基类对象?

    ②、派生类对象引用自动转化为基类对象引用。
    ③、派生类对象自动转换为基类对象(特有的成员消失)。
  • 当派生类以private/protected方式继承基类时
    ④、派生类对象指针(引用)转化为基类对象指针(引用)需用强制类型转化。但不能用static_cast,要用reinterpret_cast。
    #include 
    #include
    using namespace std;class Employee {
    //员工类public: Employee(const string& name, const int age, const int deptno) : name_(name), age_(age), deptno_(deptno) { }private: string name_; int age_; int deptno_;};class Manager : public Employee {
    //经理类public: Manager(const string& name, const int age, const int deptno, const int level) : Employee(name, age, deptno), level_(level) { }private: int level_;};class Manager2 : private Employee {//经理类public: Manager2(const string& name, const int age, const int deptno, const int level) : Employee(name, age, deptno), level_(level) { }private: int level_;};int main(void) { Employee e1("zhangsan", 25, 20); Manager m1("lisi", 35, 20, 10); Manager2 m2("wangwu", 40, 15, 8); Employee* pe; Manager* pm; Manager2* pm2; pe = &e1;//基类指针指向派生类对象 pm = &m1;//派生类指针指向派生类对象 pm2 = &m2; pe = &m1;//派生类指针可以转化为基类指针 //pm = &e1;//基类指针无法转化为派生类指针,无法将基类对象看成是派 e1 = m1;//派生类对象自动转换为基类对象,将派生类对象看成基类对象 //会产生对象切割(派生类特有成员消失)。其对象切割英文为:object slicing pe = &m2; return 0;}

    编译:

    编译:
    另外还可以用C的方式强制进行转换:
    说到这里,来回顾一下static_cast、reinterpret_cast、cost_cast、dynamic_cast的使用场景:
    static_cast:用于编译器认可的静态转换,比如从char到int、从double到int,或者具有转换构造函数,或者重载的类型转换运算符。
    reinterpret_cast:用于编译器不认可的静态转换,比如int*转为int,在转型的过程中,不做任何对齐。
    const_cast去除常量性。
    以上都是静态转换,不需要运行时的支持,下面的这个是动态转换,需要运行时的支持:
    dynamic_cast:用于动态转换,安全的向下转型。这个在之后的多态会学习~

    ⑤、不能把派生类对象强制转换为基类对象。
    那如果强制转换行不行呢?

  • 基类对象指针(引用)可用强制类型转换为派生类对象指针(引用), 而基类对象无法执行这类转换。
    但是可以通过强制转换:
    那如果是对象,而不是指针呢?
    这样不行,那可以用强制转换么?
  • 向下转型不安全,没有自动转换的机制。
    为什么不安全呢?因为指针是指向基类的,但是强制转换成了派生类指针,则就有可能去访问派生类的特定成员,如level_,但是它不属于基类的,所以就不安全了。
    从语法上来说,有没有办法能实现基类对象转换成派生类对象呢?答案是肯定的,下面来实现一下,仅仅是说明一下语法,没有任何实际意义:
    方法一:利用转换构造函数来实现:
    #include 
    #include
    using namespace std;class Employee {
    //员工类public: Employee(const string& name, const int age, const int deptno) : name_(name), age_(age), deptno_(deptno) { }private: string name_; int age_; int deptno_;};class Manager : public Employee {
    //经理类public: Manager(const string& name, const int age, const int deptno, const int level) : Employee(name, age, deptno), level_(level) { } Manager(const Employee& other) : Employee(other), level_(-1) {//转换构造函数,没有意义,仅说明语法 }private: int level_;};int main(void) { Employee e1("zhangsan", 25, 20); Manager m1("lisi", 35, 20, 10); m1 = e1; return 0;}

    编译:

    方法二:类型转换运算符重载:

    #include 
    #include
    using namespace std;class Manager;//由于Employee用到了Manager,而它在后面声明的,所以需要做个前向声明class Employee {
    //员工类public: Employee(const string& name, const int age, const int deptno) : name_(name), age_(age), deptno_(deptno) { } operator Manager();private: string name_; int age_; int deptno_;};Employee::operator Manager() { return Manager(name_, age_, deptno_, -1);}class Manager : public Employee {
    //经理类public: Manager(const string& name, const int age, const int deptno, const int level) : Employee(name, age, deptno), level_(level) { }private: int level_;};int main(void) { Employee e1("zhangsan", 25, 20); Manager m1("lisi", 35, 20, 10); m1 = e1; return 0;}

    编译:

    由于Manager是在运算符重载方法之后申明的,所以编译通不过,这时可以将它放到Manager声明之后:
    这样就可以编译通过了,由于在代码是写在同一个类中,所以就存在先后顺序的问题,如果类是分开在不同的cpp中定义的,就不会存在这个问题了。

转载于:https://www.cnblogs.com/webor2006/p/5559030.html

你可能感兴趣的文章
QT学习:c++解析html相关
查看>>
Java -Dfile.encoding=UTF-8 干掉乱码
查看>>
[转]Jenkins HTML报告样式无法显示问题解决
查看>>
linux文件与目录管理(1)
查看>>
android学习记录(十三)Task 和 Activity 回退栈操作。
查看>>
EasyUI禁用控制方法常采用
查看>>
C++ 在dynamic_cast<>用法
查看>>
Solr使用入门指南
查看>>
Android 手机设置CMWAP 接入点
查看>>
3Sum Closest
查看>>
从此不再惧怕URI编码:JavaScript及C# URI编码详解(转)
查看>>
使用X-UA-Compatible来设置IE8兼容模式
查看>>
Python3.5-20190502-廖老师-自我笔记
查看>>
人力资源匹配数据表设计
查看>>
iOS-证书真机调试
查看>>
APP的六种loading加载样式,全在这...
查看>>
java基础
查看>>
玩转cocos2d-x lua-binding, 实现c++与lua混合编程
查看>>
Implement the Singleton In AS3
查看>>
一、Redis 服务相关命令
查看>>