C++数据类型
C++数据类型
普通类型
着重讲一下与C不同的类型.
-
wchar_t为了输出输入双字节的东西,有
wchar_t类型,也有wcin和wcout处理,但是我看可以直接输出中文,也许是进步了吧.是由一种内置的整型组成的,可能随系统变化. -
char16_t,char32_tC++11引入的,长16位,32位,无符号.是由一种内置的整型组成的,可能随系统变化.
-
bool -
浮点型
主要是一点,可以在数字后面标记f,F,l,L来表示浮点型,虽然知道,但是强调一下.
-
R"(原始字符串)",无需转义 -
L"",表示是宽字符,也就是上面的wchar_t -
nullptr:用于赋值空指针.C++ 不允许直接将
void *隐式转换到其他类型,从而((void*)0)不是NULL的合法实现,而是用0来赋值用无法解决重载的混乱.故而创造了它,用来隐式转换.
多类型结构
结构体
与数组一样,C++11也支持将列表初始化用于结构,且等号(=)是可选的:
inflatable duck ["Daphne",0.12,9.98];//can omit the in C++11
可以声明匿名结构体来保证后续无法再次创建.
有位字段:
struct torgle_register{
unsigned int sb : 4;
bool goonIn : 1;
}
class关键字与struct关键字等同.
联合体
单纯的union就不多说了.在C++17 引入了std::visit和std::variant,这是一种类型安全的联合体实现.
std::variant 是一个模板类,可以存储几种不同类型中的一个值。它的声明如下:
template<class... Types>
class variant;
//上面为声明,下面为基本用法
#include <variant>
#include <string>
#include <iostream>
int main() {
std::variant<int, float, std::string> v;
v = 42; // v 现在包含 int
std::cout << std::get<int>(v) << std::endl; // 输出:42
v = 3.14f; // v 现在包含 float
std::cout << std::get<float>(v) << std::endl; // 输出:3.14
v = "hello"; // v 现在包含 string
std::cout << std::get<std::string>(v) << std::endl; // 输出:hello
// 使用 std::get_if 安全地获取值
if (const auto intPtr = std::get_if<int>(&v)) {
std::cout << "It's an int: " << *intPtr << std::endl;
} else {
std::cout << "It's not an int" << std::endl;
}
}
但是为了更高效(而非简单用get)访问它,就出现了visit:
//基本用法
//这里的 visitor 是一个**可调用对象 (Callable)**,它必须能够接受 variant 中所有可能类型的参数。
std::visit(visitor, variant);
//使用函数对象(仿函数)作为访问者
//MyVisitor 必须为 int、double 和 std::string 都提供一个 operator() 重载。如果漏掉任何一个,代码将无法编译通过。这就是 std::visit 的类型安全性的体现。
#include <iostream>
#include <variant>
#include <string>
// 1. 定义一个 variant
using MyVariant = std::variant<int, double, std::string>;
// 2. 定义一个访问者结构体
struct MyVisitor {
void operator()(int i) const {
std::cout << "Visited an int: " << i << std::endl;
}
void operator()(double d) const {
std::cout << "Visited a double: " << d << std::endl;
}
void operator()(const std::string& s) const {
std::cout << "Visited a string: " << s << std::endl;
}
};
int main() {
MyVariant v = "hello";
// 3. 使用 std::visit
std::visit(MyVisitor{}, v); // 输出: Visited a string: hello
v = 123;
std::visit(MyVisitor{}, v); // 输出: Visited an int: 123
}
//使用 Lambda 和 Overload 模式
//直接写多个 Lambda 是无法构成一个重载集的。为了解决这个问题,社区发明了一种非常优雅的 "overload" 或 "overloaded" 模式。你需要一个辅助的结构体来将多个 Lambda 组合成一个重载集。
//这种方式代码更内聚,不需要在别处定义一个结构体,是目前最受推崇的用法。
#include <iostream>
#include <variant>
#include <string>
// 辅助模板,用于组合多个 Lambda
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
// C++17 的类模板参数推导指引,使得我们不需要手动指定模板参数
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
int main() {
std::variant<int, double, std::string> v = 3.14;
// 将多个 Lambda 组合成一个访问者
auto visitor = overloaded {
[](int i) { std::cout << "Lambda saw an int: " << i << std::endl; },
[](double d) { std::cout << "Lambda saw a double: " << d << std::endl; },
[](const std::string& s) { std::cout << "Lambda saw a string: " << s << std::endl; }
};
std::visit(visitor, v); // 输出: Lambda saw a double: 3.14
}
std::visit 是有返回值的。它的返回值类型由访问者所有 operator() 的共同返回类型决定。
std::variant<int, std::string> v = "world";
auto visitor = overloaded {
[](int i) { return std::string("from int: ") + std::to_string(i); },
[](const std::string& s) { return std::string("from string: ") + s; }
};
// 所有的 operator() 都返回 std::string,所以 visit 的结果也是 std::string
std::string result = std::visit(visitor, v);
std::cout << result << std::endl; // 输出: from string: world
如果不同重载的返回类型不一致,会导致编译错误。
另外std::visit 一个非常强大的功能是它可以同时访问多个 variant。它会取出每个 variant 的当前值,然后将这些值一起传递给访问者。
std::variant<int, float> v1 = 10;
std::variant<long, float> v2 = 2.5f;
auto visitor = overloaded {
// 处理 (int, long), (int, float), (float, long), (float, float) 所有组合
[](auto arg1, auto arg2) {
std::cout << "Combination: " << arg1 + arg2 << std::endl;
},
// 你也可以为特定组合提供重载
[](int i, long l) {
std::cout << "Specific combo (int, long): " << i + l << std::endl;
}
};
// visit 会根据 v1 和 v2 的当前类型,选择最匹配的重载
std::visit(visitor, v1, v2); // v1是int, v2是float。会匹配第一个泛型Lambda
// 如果 v2 是 long 类型,则会匹配第二个重载
这在处理状态机或者需要组合不同类型状态的场景下非常有用。
枚举
enum 枚举,和c一样,都是枚举量,将数值直接赋值他们是会报错的,但是枚举量赋值枚举量是可以的,显式赋值enum bits{one ,two = 2, three};
这里one为0,two为2,three为3.也可以同时是一个数字,就不举例了.
在 C++11 中引入的enum class,相比之下有许多优势,建议直接使用.优势如下:不会出现命名混淆(enum居然没有自己的命名空间),不允许类型混淆,可以指定底层类型enum class name : char {...},支持声明.是一种类型安全的实现.

浙公网安备 33010602011771号