Skip to content

Instantly share code, notes, and snippets.

@pengfeiw
Created May 8, 2025 09:19
Show Gist options
  • Select an option

  • Save pengfeiw/10a2e0f2a2f51686d19fb419678bdf7a to your computer and use it in GitHub Desktop.

Select an option

Save pengfeiw/10a2e0f2a2f51686d19fb419678bdf7a to your computer and use it in GitHub Desktop.
implicit cast in c++

普通隐式转换

当一个值拷贝给另一个兼容类型的值时,隐式转换会自动进行。

short a=2000;
int b;
b=a;

数字的隐式转换可能会存在数据丢失(数据截断)

对于非基本类型,数组和函数可以隐式转换成指针。

不同类型间的指针也允许互相转换。

  • NULL 指针允许转换成任意类型的指针。
  • 任意类型的指针可以转换成 void 指针。
  • 派生类的指针可以转换成基类指针,但是不会改变它的 const 或者 volatile 属性。
  • T* 可以转换成 const T*,但反过来不行。

类的隐式转换

除了上述内置的隐式转换,C++ 允许用户自定义类型转换。在类中有两种方式:

  • 类型转换操作符(Typecast Operators)
  • 转换构造函数(Converting Constructors)

类型转换操作符

第一个例子。

自定义了 Vector 结构,通过重载 bool 操作符,可以将 Vector 当作 bool 变量使用,当 x && y && && z 为 true 时,Vector 就为 true,否则为 false。

#include <iostream>

struct Vector {
  float x;
  float y;
  float z;

  // Return true if all of the components
  // of the vector are truthy
  operator bool() const {
    return x && y && z;
  }
};

int main() {
  Vector A { 1, 2, 3 };
  Vector B { 0, 0, 0 };

  // We can now treat Vectors as booleans
  if (A) {
    std::cout << "A is Truthy";
  }

  if (B) {
    std::cout << "B is Truthy";
  }
}

第二个例子。

在 Player 中定义了一个 operator Party() ,达到将 Player 转换成 Party 的功能。

#include <iostream>

// Forward-declaring an incomplete type so
// it can be used within the Party class
class Player;

class Party {
public:
  Party(const Player* Leader)
    : Leader { Leader } {
    std::cout << "A party was created\n";
  }

  const Player* Leader;
};

class Player {
public:
  std::string Name;

  // Allow a Player to be converted to a Party
  operator Party() const {
    return Party { this };
  }
};

// This function accepts parties - not players
void StartQuest(Party Party) {
  std::cout << Party.Leader->Name
       << "'s party has started the quest";
}

int main() {
  Player Frodo { "Frodo" };
  // Because Players can now be implicitly
  // converted to parties we can pass a Player
  // argument into a Party parameter
  StartQuest(Frodo);
}

转换构造函数

如果一个类定义了一个非 explicit 的单参数构造函数,实际上就允许参数类型自动转换成该类型。

struct Vector {
  Vector(float ComponentSize) :
    x { ComponentSize },
    y { ComponentSize },
    z { ComponentSize } {}

  float x;
  float y;
  float z;
};

void Move(Vector Direction) {
  // ...
}

int main() {
  Move(5.f);
}

更为恼火的是下面的代码仍然能够编译通过。

...
void Move(Vector Direction) {
  // ...
}

int main() {
  Move(true);
}

实际上 true 隐式转换成了 float,然后 float 通过转换构造函数转换成了 Vector 类型。

禁止类的隐式转换

为了避免这些隐式转换,可以在函数声明标记 explicit

struct Vector {
  explicit Vector(float ComponentSize) :
    x { ComponentSize },
    y { ComponentSize },
    z { ComponentSize } {}
....
}
struct MyType {
  // 添加 explicit 关键字,禁止通过该操作符进行隐式转换
  explicit operator int() {
    return 1;
  }
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment