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

  • 相关阅读:
    Do You See Me? Ethical Considerations of the Homeless
    ELDER HOMELESSNESS WHY IS THIS AN ISSUE?
    Endoflife support is lacking for homeless people
    html内联框架
    html字体
    html块 div span
    html列表
    html表格
    SQL Server管理员专用连接的使用   作为一名DBA,经常会处理一些比较棘手的服务无响应问题,鉴于事态的严重性,多数DBA可能直接用“重启”大法,以便尽快的恢复生产环境的正常运转,但是多数情况
    如何配置最大工作线程数 (SQL Server Management Studio)
  • 原文地址:https://www.cnblogs.com/webor2006/p/5559030.html
Copyright © 2011-2022 走看看