zoukankan      html  css  js  c++  java
  • 继续(三)

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

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

      下面用代码进行说明:

      #include <iostream>
      #include <string>
      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 <iostream>
      #include <string>
      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 <iostream>
      #include <string>
      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 <iostream>
      #include <string>
      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中定义的,就不会存在这个问题了。

  • 相关阅读:
    Extjs4单选按钮
    下拉框comboxBox本地数据源示例
    处理您的请求时发生异常。此外,对第一个异常执行自定义错误页时发生另一异常。已终止请
    hoj1568
    hoj3434
    poj2924
    poj2909
    hoj3433
    理解Python闭包,这应该是最好的例子
    Spring 学习笔记
  • 原文地址:https://www.cnblogs.com/webor2006/p/5559030.html
Copyright © 2011-2022 走看看