`implicit_cast`与`down_cast`的使用

在看muduo源码的时候看到了implicit_castdown_cast,这里顺便做个笔记。

  • implicit_castdown_cast用在有继承关系的类间转换;
  • implicit_cast用于向上转型(子类指针–>父类指针);
  • down_cast用于向下类型转换(父类指针–>子类指针);

示例:

#include <iostream>

#ifndef NDEBUG
#include <cassert>
#endif

using namespace std;

namespace showcode {

///
/// @brief  `implicit_cast` 用于向上转型
/// From: subclass    
/// To  : father of subclass
///
template <typename To, typename From>
inline To implicit_cast(const From& f) {
  return f;
}

///
/// @brief  `down_cast` 用于向下转型
/// From: father of subclass
/// To  : subclass
///
template<typename To, typename From>     // use like this: down_cast<T*>(foo);
inline To down_cast(From* f)                     // so we only accept pointers
{
  // Ensures that To is a sub-type of From *.  This test is here only
  // for compile-time type checking, and has no overhead in an
  // optimized build at run-time, as it will be optimized away
  // completely.
  if (false)
  {
    implicit_cast<From*, To>(0);
  }

#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
  assert(f == NULL || dynamic_cast<To>(f) != NULL);  // RTTI: debug mode only!
#endif
  return static_cast<To>(f);
}

} // namespace showcode


class Base {
public:
  Base() = default;
  virtual ~Base() = default;

  virtual void Print() const {
    cout << __FUNCTION__ << endl;
  }
};

class Derived : public Base {
public:
  Derived() = default;
  ~Derived() = default;

  void Print() const override {
    cout << __FUNCTION__ << endl;
  }
};

int main() {
  { // 普通类型转型
    cout << "----------------普通类型转型--------------------" << endl;
    int a = 10;
    double b = showcode::implicit_cast<double>(a);
    cout << typeid(b).name() << " b: " << b << endl;
    cout << endl;
  }

  { // 向上转型
    cout << "----------------向上转型--------------------" << endl;
    Derived* pd = new Derived;
    Base* pb = showcode::implicit_cast<Base*>(pd);
    pb->Print();
    cout << endl;
  }

  { // 通常用法
    cout << "----------------通常向下转型用法--------------------" << endl;
    Base* pb = new Base;
    pb->Print();
    if (Derived* pd = dynamic_cast<Derived*>(pb)) { // 这一步是nullptr的,直到运行时才知道
      pd->Print();
    }
    cout << endl;
  }

  { // 向下转型
    cout << "----------------向下转型--------------------" << endl;
    Base* pb = new Base;
    Derived* pd = showcode::down_cast<Derived*>(pb); // 编译期间就知道错误了
    pd->Print();
    cout << endl;
  }
  return 0;
}

运行结果:

  • Debug模式下:Derived* pd = showcode::down_cast<Derived*>(pb);报错;
    在这里插入图片描述
  • Release模式下:
    在这里插入图片描述
    没有报错,因为Release模式下的down_cast用的就是static_cast

问题:
(1)为什么implicit_caststatic_cast安全?
implicit_cast只用于隐式类型转换,而static_cast向上向下都行,但显然向下类型转换是不安全的。

  • 先来说说隐式转换,比如有如下的定义:
class Base {};
class Derived : public Base {
public:
  Derived() {
    data = 100;
  }
  void Print() const {
    cout << data << endl;
  }
private:
  int data;
};
int main() {
  Base* b;
  Derived* d;
  b = d;      // ok
  //d = b;    // error: 不允许向上的隐式转换 
  d = static_cast<Derived*>(b); // ok, 但不是安全的


  Base* pb = new Base;
  Derived* pd = static_cast<Derived*>(pb);  // ok, 但不是安全的
  pd->Print();  // 打印的是一个无意义的值
  return 0;
}

上面使用static_cast向下转换是不安全的,但是程序并没有报错,而如果我们使用implicit_castdown_cast的话,则可以查出错误。

Base* pb = new Base;
Derived* pd = implicit_cast<Derived*>(pb);	// error
Derived* pd2 = static_cast<Derived*>(pb);	// ok, 但是不安全

子类可以隐式转换成父类(借助虚函数表),而父类无法隐式转换成子类(因为父类中没有子类的信息)。

参考:隐式转型(向上转型,即将派生类对象赋值给基类)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值