C++ 修饰符类型
概述
修饰符(Modifiers)是C++中用于修改基本数据类型特性的关键字。它们可以改变变量的符号性、大小、存储位置等属性。理解和正确使用修饰符对于编写高效、正确的C++程序至关重要。
🔢 符号修饰符
signed和unsigned
cpp
#include <iostream>
#include <limits>
int main() {
// signed修饰符(默认情况)
signed char s_char = -128;
signed int s_int = -2147483648;
signed short s_short = -32768;
// unsigned修饰符
unsigned char u_char = 255;
unsigned int u_int = 4294967295U;
unsigned short u_short = 65535;
// 输出范围信息
std::cout << "=== signed类型范围 ===" << std::endl;
std::cout << "signed char: "
<< static_cast<int>(std::numeric_limits<signed char>::min())
<< " 到 "
<< static_cast<int>(std::numeric_limits<signed char>::max()) << std::endl;
std::cout << "signed int: "
<< std::numeric_limits<signed int>::min()
<< " 到 "
<< std::numeric_limits<signed int>::max() << std::endl;
std::cout << "\n=== unsigned类型范围 ===" << std::endl;
std::cout << "unsigned char: "
<< static_cast<int>(std::numeric_limits<unsigned char>::min())
<< " 到 "
<< static_cast<int>(std::numeric_limits<unsigned char>::max()) << std::endl;
std::cout << "unsigned int: "
<< std::numeric_limits<unsigned int>::min()
<< " 到 "
<< std::numeric_limits<unsigned int>::max() << std::endl;
// 展示值
std::cout << "\n=== 实际值 ===" << std::endl;
std::cout << "signed char: " << static_cast<int>(s_char) << std::endl;
std::cout << "unsigned char: " << static_cast<int>(u_char) << std::endl;
std::cout << "signed int: " << s_int << std::endl;
std::cout << "unsigned int: " << u_int << std::endl;
return 0;
}符号修饰符的使用场景
cpp
#include <iostream>
// 年龄只能为正数,使用unsigned
void print_age(unsigned int age) {
std::cout << "年龄: " << age << " 岁" << std::endl;
}
// 温度可以为负数,使用signed
void print_temperature(signed int temperature) {
std::cout << "温度: " << temperature << "°C" << std::endl;
}
// 字节操作通常使用unsigned char
void print_bytes(const unsigned char* data, size_t length) {
std::cout << "字节数据: ";
for (size_t i = 0; i < length; ++i) {
std::cout << static_cast<int>(data[i]) << " ";
}
std::cout << std::endl;
}
int main() {
// 合适的使用场景
print_age(25); // 年龄为正数
print_temperature(-10); // 温度可为负数
print_temperature(30); // 温度也可为正数
// 字节操作
unsigned char bytes[] = {0xFF, 0x00, 0xAB, 0xCD};
print_bytes(bytes, sizeof(bytes));
// 注意溢出问题
unsigned int small_unsigned = 0;
std::cout << "unsigned减1前: " << small_unsigned << std::endl;
small_unsigned--; // 下溢,变成很大的正数
std::cout << "unsigned减1后: " << small_unsigned << std::endl;
return 0;
}📏 大小修饰符
short、long和long long
cpp
#include <iostream>
#include <climits>
int main() {
// 基本整数类型
short short_int = 32767;
int normal_int = 2147483647;
long long_int = 2147483647L;
long long long_long_int = 9223372036854775807LL;
// 可以省略int关键字
short s = 100;
long l = 200L;
long long ll = 300LL;
// 输出大小信息
std::cout << "=== 类型大小 ===" << std::endl;
std::cout << "short: " << sizeof(short) << " 字节" << std::endl;
std::cout << "int: " << sizeof(int) << " 字节" << std::endl;
std::cout << "long: " << sizeof(long) << " 字节" << std::endl;
std::cout << "long long: " << sizeof(long long) << " 字节" << std::endl;
// 输出范围信息
std::cout << "\n=== 类型范围 ===" << std::endl;
std::cout << "short: " << SHRT_MIN << " 到 " << SHRT_MAX << std::endl;
std::cout << "int: " << INT_MIN << " 到 " << INT_MAX << std::endl;
std::cout << "long: " << LONG_MIN << " 到 " << LONG_MAX << std::endl;
std::cout << "long long: " << LLONG_MIN << " 到 " << LLONG_MAX << std::endl;
// 组合使用
unsigned short us = 65535;
unsigned long ul = 4294967295UL;
unsigned long long ull = 18446744073709551615ULL;
std::cout << "\n=== 无符号类型 ===" << std::endl;
std::cout << "unsigned short: " << us << std::endl;
std::cout << "unsigned long: " << ul << std::endl;
std::cout << "unsigned long long: " << ull << std::endl;
return 0;
}选择合适的整数类型
cpp
#include <iostream>
#include <cstdint> // 固定宽度整数类型
// 不同场景下的类型选择
void demonstrate_type_selection() {
// 1. 一般用途:使用int
int counter = 0;
int array_size = 100;
// 2. 循环索引:使用size_t(无符号)
std::vector<int> data = {1, 2, 3, 4, 5};
for (size_t i = 0; i < data.size(); ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
// 3. 内存大小:使用size_t
size_t memory_size = sizeof(data);
std::cout << "内存大小: " << memory_size << " 字节" << std::endl;
// 4. 大数值:使用long long
long long population = 7800000000LL; // 全球人口
std::cout << "全球人口: " << population << std::endl;
// 5. 精确宽度需求:使用固定宽度类型
std::int32_t precise_32bit = 1000000;
std::uint64_t precise_64bit = 1000000000000ULL;
std::cout << "32位整数: " << precise_32bit << std::endl;
std::cout << "64位无符号整数: " << precise_64bit << std::endl;
// 6. 文件偏移等:使用适当的类型
std::streamoff file_offset = 1024;
std::cout << "文件偏移: " << file_offset << std::endl;
}
int main() {
demonstrate_type_selection();
return 0;
}📍 存储类修饰符
auto、register、static、extern
cpp
#include <iostream>
// 全局变量
int global_var = 100;
// extern声明(变量定义在其他文件中)
extern int external_var; // 假设在其他文件中定义
// 静态全局变量(仅在当前文件可见)
static int file_static_var = 200;
void demonstrate_storage_classes() {
// 1. auto(C++11前的用法,现已改变)
// 在C++11之前,auto表示自动存储期,但通常省略
// 现在auto用于类型推导
auto automatic_var = 42; // 现代C++中的auto
// 2. register(提示编译器优化)
// 注意:C++17中register被废弃
// register int fast_var = 10; // 不推荐使用
// 3. static局部变量(保持值在函数调用之间)
static int call_count = 0;
call_count++;
std::cout << "函数调用次数: " << call_count << std::endl;
// 4. 局部变量(自动存储期)
int local_var = 300;
std::cout << "局部变量: " << local_var << std::endl;
// 访问全局变量
std::cout << "全局变量: " << global_var << std::endl;
std::cout << "文件静态变量: " << file_static_var << std::endl;
}
// 静态函数(仅在当前文件可见)
static void static_function() {
std::cout << "静态函数调用" << std::endl;
}
// extern函数声明
extern void external_function(); // 定义在其他地方
int main() {
std::cout << "=== 存储类演示 ===" << std::endl;
// 多次调用以观察static变量的行为
demonstrate_storage_classes();
demonstrate_storage_classes();
demonstrate_storage_classes();
static_function();
return 0;
}静态成员
cpp
#include <iostream>
class Counter {
private:
static int total_count_; // 静态成员变量
int instance_id_; // 实例成员变量
public:
// 构造函数
Counter() {
total_count_++;
instance_id_ = total_count_;
std::cout << "创建对象 #" << instance_id_ << std::endl;
}
// 析构函数
~Counter() {
std::cout << "销毁对象 #" << instance_id_ << std::endl;
}
// 静态成员函数
static int getTotalCount() {
// 只能访问静态成员
return total_count_;
// return instance_id_; // 错误!不能访问实例成员
}
// 实例成员函数
int getInstanceId() const {
return instance_id_;
}
// 静态成员函数:重置计数器
static void resetCounter() {
total_count_ = 0;
}
};
// 静态成员定义(必须在类外定义)
int Counter::total_count_ = 0;
void demonstrate_static_members() {
std::cout << "初始计数: " << Counter::getTotalCount() << std::endl;
{
Counter c1, c2, c3;
std::cout << "当前总数: " << Counter::getTotalCount() << std::endl;
std::cout << "c2的ID: " << c2.getInstanceId() << std::endl;
} // c1, c2, c3在这里被销毁
std::cout << "作用域结束后总数: " << Counter::getTotalCount() << std::endl;
// 重置计数器
Counter::resetCounter();
std::cout << "重置后计数: " << Counter::getTotalCount() << std::endl;
}
int main() {
demonstrate_static_members();
return 0;
}🔧 类型限定符
const、volatile、mutable
cpp
#include <iostream>
#include <thread>
#include <chrono>
// volatile示例:硬件寄存器或多线程共享变量
volatile int hardware_register = 0;
class VolatileExample {
private:
volatile bool running_; // volatile成员
mutable int access_count_; // mutable成员
const int id_; // const成员
public:
VolatileExample(int id) : running_(true), access_count_(0), id_(id) {}
// const成员函数中修改mutable成员
bool isRunning() const {
access_count_++; // 可以修改mutable成员
return running_; // volatile确保每次都从内存读取
}
void stop() {
running_ = false; // volatile确保立即写入内存
}
int getAccessCount() const {
return access_count_;
}
int getId() const {
return id_; // const成员不能修改
}
};
// 线程函数,用于演示volatile
void worker_thread(VolatileExample* obj) {
int count = 0;
while (obj->isRunning()) {
count++;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (count > 10) {
obj->stop();
}
}
std::cout << "工作线程结束,循环了 " << count << " 次" << std::endl;
}
int main() {
std::cout << "=== 类型限定符演示 ===" << std::endl;
// const变量
const int MAX_SIZE = 100;
std::cout << "常量: " << MAX_SIZE << std::endl;
// volatile变量(模拟硬件寄存器)
hardware_register = 42;
std::cout << "硬件寄存器值: " << hardware_register << std::endl;
// mutable示例
VolatileExample example(1);
std::cout << "对象ID: " << example.getId() << std::endl;
// 多次调用const函数,观察mutable成员的变化
for (int i = 0; i < 5; ++i) {
example.isRunning();
}
std::cout << "访问次数: " << example.getAccessCount() << std::endl;
// 线程示例(演示volatile的作用)
std::cout << "\n=== 多线程示例 ===" << std::endl;
VolatileExample thread_example(2);
std::thread worker(worker_thread, &thread_example);
// 主线程等待
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "主线程检查状态..." << std::endl;
worker.join();
std::cout << "线程演示结束" << std::endl;
return 0;
}const的深入应用
cpp
#include <iostream>
#include <vector>
#include <memory>
class ConstCorrectness {
private:
std::vector<int> data_;
mutable bool cache_valid_;
mutable int cached_sum_;
public:
ConstCorrectness(std::initializer_list<int> values)
: data_(values), cache_valid_(false), cached_sum_(0) {}
// const成员函数重载
const int& at(size_t index) const {
return data_.at(index);
}
int& at(size_t index) {
cache_valid_ = false; // 非const版本可能修改数据
return data_.at(index);
}
// const成员函数,但内部有缓存逻辑
int sum() const {
if (!cache_valid_) {
cached_sum_ = 0;
for (const auto& value : data_) {
cached_sum_ += value;
}
cache_valid_ = true;
std::cout << "计算并缓存求和结果" << std::endl;
} else {
std::cout << "使用缓存的求和结果" << std::endl;
}
return cached_sum_;
}
void add(int value) {
data_.push_back(value);
cache_valid_ = false;
}
size_t size() const {
return data_.size();
}
};
// 函数重载:const和非const版本
void process_data(ConstCorrectness& data) {
std::cout << "处理非const数据" << std::endl;
data.add(100); // 可以修改
}
void process_data(const ConstCorrectness& data) {
std::cout << "处理const数据" << std::endl;
std::cout << "大小: " << data.size() << std::endl;
std::cout << "求和: " << data.sum() << std::endl;
}
int main() {
std::cout << "=== const正确性演示 ===" << std::endl;
ConstCorrectness data{1, 2, 3, 4, 5};
// 非const对象
std::cout << "\n--- 非const对象 ---" << std::endl;
process_data(data);
std::cout << "修改后求和: " << data.sum() << std::endl;
// const对象
std::cout << "\n--- const对象 ---" << std::endl;
const ConstCorrectness const_data{10, 20, 30};
process_data(const_data);
// 再次调用sum(),观察缓存效果
std::cout << "再次求和: " << const_data.sum() << std::endl;
// 指针和const
std::cout << "\n--- 指针和const ---" << std::endl;
const ConstCorrectness* ptr_to_const = &data;
// ptr_to_const->add(200); // 错误!不能通过const指针修改
std::cout << "通过const指针访问: " << ptr_to_const->size() << std::endl;
return 0;
}🎯 修饰符组合
修饰符的组合使用
cpp
#include <iostream>
// 各种修饰符的组合
class ModifierCombinations {
private:
// 基本组合
static const int STATIC_CONST = 100;
static const unsigned long STATIC_CONST_ULONG = 1000000UL;
// 复杂组合
mutable volatile unsigned short status_;
const volatile int* hardware_ptr_;
public:
ModifierCombinations()
: status_(0), hardware_ptr_(nullptr) {}
// 各种函数修饰符组合
static const unsigned int getStaticConstValue() {
return STATIC_CONST;
}
const volatile unsigned short getStatus() const {
return status_;
}
void updateStatus(unsigned short new_status) {
status_ = new_status;
}
};
// 函数参数的修饰符组合
void complex_function(
const unsigned long long* const ptr, // 指向const unsigned long long的const指针
volatile unsigned char& ref, // volatile unsigned char的引用
const volatile short value // const volatile short值
) {
std::cout << "复杂函数参数处理" << std::endl;
std::cout << "指针指向的值: " << *ptr << std::endl;
std::cout << "引用的值: " << static_cast<int>(ref) << std::endl;
std::cout << "值参数: " << value << std::endl;
}
int main() {
std::cout << "=== 修饰符组合演示 ===" << std::endl;
ModifierCombinations obj;
// 访问静态const成员
std::cout << "静态常量值: " << obj.getStaticConstValue() << std::endl;
// 状态操作
obj.updateStatus(42);
std::cout << "状态值: " << obj.getStatus() << std::endl;
// 复杂函数调用
const unsigned long long big_value = 9876543210ULL;
volatile unsigned char byte_value = 255;
const volatile short short_value = -1000;
complex_function(&big_value, byte_value, short_value);
// 展示各种类型的大小
std::cout << "\n=== 类型大小信息 ===" << std::endl;
std::cout << "unsigned short: " << sizeof(unsigned short) << " 字节" << std::endl;
std::cout << "const long: " << sizeof(const long) << " 字节" << std::endl;
std::cout << "volatile int: " << sizeof(volatile int) << " 字节" << std::endl;
std::cout << "unsigned long long: " << sizeof(unsigned long long) << " 字节" << std::endl;
return 0;
}现代C++中的修饰符
cpp
#include <iostream>
#include <type_traits>
// C++11及以后的修饰符
class ModernModifiers {
private:
// constexpr成员
static constexpr int COMPILE_TIME_CONST = 42;
static constexpr double PI = 3.14159;
// auto成员(需要初始化)
// C++17: 可以在类内使用auto
static inline auto class_name = "ModernModifiers";
public:
// constexpr构造函数
constexpr ModernModifiers() = default;
// constexpr成员函数
constexpr int getConstValue() const {
return COMPILE_TIME_CONST;
}
// C++14: constexpr可以包含更复杂的逻辑
constexpr int fibonacci(int n) const {
if (n <= 1) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
// C++17: constexpr if
template<typename T>
constexpr auto process(T value) const {
if constexpr (std::is_integral_v<T>) {
return value * 2;
} else {
return value + 1.0;
}
}
};
// C++20: consteval(强制编译时求值)
#if __cpp_consteval >= 201811L
consteval int compile_time_only(int x) {
return x * x; // 必须在编译时计算
}
#endif
int main() {
std::cout << "=== 现代C++修饰符 ===" << std::endl;
constexpr ModernModifiers obj;
// 编译时计算
constexpr int const_value = obj.getConstValue();
constexpr int fib_10 = obj.fibonacci(10);
std::cout << "编译时常量: " << const_value << std::endl;
std::cout << "第10个斐波那契数: " << fib_10 << std::endl;
// constexpr if示例
constexpr auto int_result = obj.process(42);
constexpr auto double_result = obj.process(3.14);
std::cout << "整数处理结果: " << int_result << std::endl;
std::cout << "浮点处理结果: " << double_result << std::endl;
// C++20 consteval
#if __cpp_consteval >= 201811L
constexpr auto square_5 = compile_time_only(5);
std::cout << "编译时平方: " << square_5 << std::endl;
#endif
// 类型特征检查
std::cout << "\n=== 类型特征 ===" << std::endl;
std::cout << "const int 是const: " << std::is_const_v<const int> << std::endl;
std::cout << "volatile int 是volatile: " << std::is_volatile_v<volatile int> << std::endl;
std::cout << "unsigned int 是无符号: " << std::is_unsigned_v<unsigned int> << std::endl;
return 0;
}总结
C++修饰符类型提供了丰富的方式来精确控制数据的特性:
修饰符分类
- 符号修饰符:signed/unsigned - 控制数值的符号性
- 大小修饰符:short/long/long long - 控制数据大小
- 存储类修饰符:static/extern/auto - 控制存储和链接
- 类型限定符:const/volatile/mutable - 控制访问和优化
使用原则
- 选择合适的符号性:根据数据范围选择signed或unsigned
- 考虑性能和内存:根据需要选择合适的大小修饰符
- 正确使用const:提高代码安全性和可读性
- 谨慎使用volatile:主要用于硬件访问和多线程编程
现代C++改进
- constexpr提供编译时计算能力
- auto简化类型声明
- 更强的类型安全检查
- 更好的优化支持
正确使用修饰符可以:
- 提高代码的正确性和安全性
- 优化内存使用和性能
- 增强代码的可读性和维护性
- 支持编译器进行更好的优化