菜鸟教程 -- 学的不仅是技术,更是梦想!

C++ 教程
C++ 教程 C++ 简介 C++ 环境设置 C++ 基本语法 C++ 注释 C++ 数据类型 C++ 变量类型 C++ 变量作用域 C++ 常量 C++ 修饰符类型 C++ 存储类 C++ 运算符 C++ 循环 C++ 判断 C++ 函数 C++ 数字 C++ 数组 C++ 字符串 C++ 指针 C++ 引用 C++ 日期 & 时间 C++ 基本的输入输出 C++ 结构体(struct) C++ vector 容器 C++ 数据结构

C++ 面向对象

C++ 类 & 对象 C++ 继承 C++ 重载运算符和重载函数 C++ 多态 C++ 数据抽象 C++ 数据封装 C++ 接口(抽象类)

C++ 高级教程

C++ 文件和流 C++ 异常处理 C++ 动态内存 C++ 命名空间 C++ 模板 C++ 预处理器 C++ 信号处理 C++ 多线程 C++ Web 编程

C++ 资源库

C++ STL 教程 C++ 导入标准库 C++ 标准库 C++ 有用的资源 C++ 实例 C++ 测验 C++ <iostream> C++ <fstream> C++ <sstream> C++ <iomanip> C++ <array> C++ <vector> C++ <list> C++ <forward_list> C++ <deque> C++ <stack> C++ <queue> C++ <priority_queue> C++ <set> C++ <unordered_set> C++ <map> C++ <unordered_map> C++ <bitset> C++ <algorithm> C++ <iterator> C++ <functional> C++ <numeric> C++ <complex> C++ <valarray> C++ <cmath> C++ <string> C++ <regex> C++ <ctime> C++ <chrono> C++ <thread> C++ <mutex> C++ <condition_variable> C++ <future> C++ <atomic> C++ <type_traits> C++ <typeinfo> C++ <exception> C++ <stdexcept> C++ <cstdio> C++ <cstdint> C++ <memory> C++ <new> C++ <utility> C++ <random> C++ <locale> C++ <codecvt> C++ <cassert> C++ <cwchar> C++ <climits> C++ <cfloat> C++ <cstdlib> C++ <numbers> C++ OpenCV
(追記) (追記ここまで)

C++ 数据类型

使用编程语言进行编程时,需要用到各种变量来存储各种信息。变量保留的是它所存储的值的内存位置。这意味着,当您创建一个变量时,就会在内存中保留一些空间。

您可能需要存储各种数据类型(比如字符型、宽字符型、整型、浮点型、双浮点型、布尔型等)的信息,操作系统会根据变量的数据类型,来分配内存和决定在保留内存中存储什么。

基本的内置类型

C++ 为程序员提供了种类丰富的内置数据类型和用户自定义的数据类型。下表列出了七种基本的 C++ 数据类型:

类型关键字
布尔型bool
字符型char
整型int
浮点型float
双浮点型double
无类型 void
宽字符型

wchar_t

其实 wchar_t 是这样来的:

typedef short int wchar_t;

所以 wchar_t 实际上的空间是和 short int 一样。

一些基本类型可以使用一个或多个类型修饰符进行修饰:

修饰符描述示例
signed表示有符号类型(默认)signed int x = -10;
unsigned表示无符号类型unsigned int y = 10;
short表示短整型short int z = 100;
long表示长整型long int a = 100000;
const表示常量,值不可修改const int b = 5;
volatile表示变量可能被意外修改,禁止编译器优化volatile int c = 10;
mutable表示类成员可以在 const 对象中修改mutable int counter;

下表显示了各种变量类型在内存中存储值时需要占用的内存,以及该类型的变量所能存储的最大值和最小值。

注意:不同系统会有所差异,一字节为 8 位。

注意:默认情况下,int、short、long都是带符号的,即 signed。

注意:long int 8 个字节,int 都是 4 个字节,早期的 C 编译器定义了 long int 占用 4 个字节,int 占用 2 个字节,新版的 C/C++ 标准兼容了早期的这一设定。

数据类型描述大小(字节)范围/取值示例
bool布尔类型,表示真或假1truefalse
char字符类型,通常用于存储 ASCII 字符1-128 到 127 或 0 到 255
signed char有符号字符类型1-128 到 127
unsigned char无符号字符类型10 到 255
wchar_t宽字符类型,用于存储 Unicode 字符2 或 4取决于平台
char16_t16 位 Unicode 字符类型(C++11 引入)20 到 65,535
char32_t32 位 Unicode 字符类型(C++11 引入)40 到 4,294,967,295
short短整型2-32,768 到 32,767
unsigned short无符号短整型20 到 65,535
int整型4-2,147,483,648 到 2,147,483,647
unsigned int无符号整型40 到 4,294,967,295
long长整型4 或 8取决于平台
unsigned long无符号长整型4 或 8取决于平台
long long长长整型(C++11 引入)8-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
unsigned long long无符号长长整型(C++11 引入)80 到 18,446,744,073,709,551,615
float单精度浮点数4约 ±3.4e±38(6-7 位有效数字)
double双精度浮点数8约 ±1.7e±308(15 位有效数字)
long double扩展精度浮点数8、12 或 16取决于平台

C++11 新增类型

数据类型描述示例
auto自动类型推断auto x = 10;
decltype获取表达式的类型decltype(x) y = 20;
nullptr空指针常量int* ptr = nullptr;
std::initializer_list初始化列表类型std::initializer_list<int> list = {1, 2, 3};
std::tuple元组类型,可以存储多个不同类型的值std::tuple<int, float, char> t(1, 2.0, 'a');

注意,各种类型的存储大小与系统位数有关,但目前通用的以64位系统为主。

以下列出了32位系统与64位系统的存储大小的差别(windows 相同):

从上表可得知,变量的大小会根据编译器和所使用的电脑而有所不同。

下面实例会输出您电脑上各种数据类型的大小。

实例

#include<iostream>#include<limits>usingnamespacestd; intmain(){cout << "type: \t\t" << "************size**************"<< endl; cout << "bool: \t\t" << "所占字节数:" << sizeof(bool); cout << "\t最大值:" << (numeric_limits<bool>::max)(); cout << "\t\t最小值:" << (numeric_limits<bool>::min)() << endl; cout << "char: \t\t" << "所占字节数:" << sizeof(char); cout << "\t最大值:" << (numeric_limits<char>::max)(); cout << "\t\t最小值:" << (numeric_limits<char>::min)() << endl; cout << "signed char: \t" << "所占字节数:" << sizeof(signedchar); cout << "\t最大值:" << (numeric_limits<signedchar>::max)(); cout << "\t\t最小值:" << (numeric_limits<signedchar>::min)() << endl; cout << "unsigned char: \t" << "所占字节数:" << sizeof(unsignedchar); cout << "\t最大值:" << (numeric_limits<unsignedchar>::max)(); cout << "\t\t最小值:" << (numeric_limits<unsignedchar>::min)() << endl; cout << "wchar_t: \t" << "所占字节数:" << sizeof(wchar_t); cout << "\t最大值:" << (numeric_limits<wchar_t>::max)(); cout << "\t\t最小值:" << (numeric_limits<wchar_t>::min)() << endl; cout << "short: \t\t" << "所占字节数:" << sizeof(short); cout << "\t最大值:" << (numeric_limits<short>::max)(); cout << "\t\t最小值:" << (numeric_limits<short>::min)() << endl; cout << "int: \t\t" << "所占字节数:" << sizeof(int); cout << "\t最大值:" << (numeric_limits<int>::max)(); cout << "\t最小值:" << (numeric_limits<int>::min)() << endl; cout << "unsigned: \t" << "所占字节数:" << sizeof(unsigned); cout << "\t最大值:" << (numeric_limits<unsigned>::max)(); cout << "\t最小值:" << (numeric_limits<unsigned>::min)() << endl; cout << "long: \t\t" << "所占字节数:" << sizeof(long); cout << "\t最大值:" << (numeric_limits<long>::max)(); cout << "\t最小值:" << (numeric_limits<long>::min)() << endl; cout << "unsigned long: \t" << "所占字节数:" << sizeof(unsignedlong); cout << "\t最大值:" << (numeric_limits<unsignedlong>::max)(); cout << "\t最小值:" << (numeric_limits<unsignedlong>::min)() << endl; cout << "double: \t" << "所占字节数:" << sizeof(double); cout << "\t最大值:" << (numeric_limits<double>::max)(); cout << "\t最小值:" << (numeric_limits<double>::min)() << endl; cout << "long double: \t" << "所占字节数:" << sizeof(longdouble); cout << "\t最大值:" << (numeric_limits<longdouble>::max)(); cout << "\t最小值:" << (numeric_limits<longdouble>::min)() << endl; cout << "float: \t\t" << "所占字节数:" << sizeof(float); cout << "\t最大值:" << (numeric_limits<float>::max)(); cout << "\t最小值:" << (numeric_limits<float>::min)() << endl; cout << "size_t: \t" << "所占字节数:" << sizeof(size_t); cout << "\t最大值:" << (numeric_limits<size_t>::max)(); cout << "\t最小值:" << (numeric_limits<size_t>::min)() << endl; cout << "string: \t" << "所占字节数:" << sizeof(string) << endl; // << "\t最大值:" << (numeric_limits<string>::max)() << "\t最小值:" << (numeric_limits<string>::min)() << endl; cout << "type: \t\t" << "************size**************"<< endl; return0; }

本实例使用了 endl,这将在每一行后插入一个换行符,<< 运算符用于向屏幕传多个值,sizeof() 运算符用来获取各种数据类型的大小。

当上面的代码被编译和执行时,它会产生以下的结果,结果会根据所使用的计算机而有所不同:

type:     ************size**************
bool:     所占字节数:1  最大值:1    最小值:0
char:     所占字节数:1  最大值:    最小值:?
signed char:   所占字节数:1  最大值:    最小值:?
unsigned char:   所占字节数:1  最大值:?    最小值:
wchar_t:   所占字节数:4  最大值:2147483647    最小值:-2147483648
short:     所占字节数:2  最大值:32767    最小值:-32768
int:     所占字节数:4  最大值:2147483647  最小值:-2147483648
unsigned:   所占字节数:4  最大值:4294967295  最小值:0
long:     所占字节数:8  最大值:9223372036854775807  最小值:-9223372036854775808
unsigned long:   所占字节数:8  最大值:18446744073709551615  最小值:0
double:   所占字节数:8  最大值:1.79769e+308  最小值:2.22507e-308
long double:   所占字节数:16  最大值:1.18973e+4932  最小值:3.3621e-4932
float:     所占字节数:4  最大值:3.40282e+38  最小值:1.17549e-38
size_t:   所占字节数:8  最大值:18446744073709551615  最小值:0
string:   所占字节数:24
type:     ************size**************

派生数据类型

数据类型描述示例
数组相同类型元素的集合int arr[5] = {1, 2, 3, 4, 5};
指针存储变量内存地址的类型int* ptr = &x;
引用变量的别名int& ref = x;
函数函数类型,表示函数的签名int func(int a, int b);
结构体用户定义的数据类型,可以包含多个不同类型的成员struct Point { int x; int y; };
用户定义的数据类型,支持封装、继承和多态class MyClass { ... };
联合体多个成员共享同一块内存union Data { int i; float f; };
枚举用户定义的整数常量集合enum Color { RED, GREEN, BLUE };

类型别名

别名描述示例
typedef为现有类型定义别名typedef int MyInt;
using为现有类型定义别名(C++11 引入)using MyInt = int;

标准库类型

数据类型描述示例
std::string字符串类型std::string s = "Hello";
std::vector动态数组std::vector<int> v = {1, 2, 3};
std::array固定大小数组(C++11 引入)std::array<int, 3> a = {1, 2, 3};
std::pair存储两个值的容器std::pair<int, float> p(1, 2.0);
std::map键值对容器std::map<int, std::string> m;
std::set唯一值集合std::set<int> s = {1, 2, 3};

typedef 声明

您可以使用 typedef 为一个已有的类型取一个新的名字。下面是使用 typedef 定义一个新类型的语法:

typedef type newname; 

例如,下面的语句会告诉编译器,feet 是 int 的另一个名称:

typedef int feet;

现在,下面的声明是完全合法的,它创建了一个整型变量 distance:

feet distance;

枚举类型

枚举类型(enumeration)是C++中的一种派生数据类型,它是由用户定义的若干枚举常量的集合。

如果一个变量只有几种可能的值,可以定义为枚举(enumeration)类型。所谓"枚举"是指将变量的值一一列举出来,变量的值只能在列举出来的值的范围内。

创建枚举,需要使用关键字 enum。枚举类型的一般形式为:

enum 枚举名{ 
 标识符[=整型常数], 
 标识符[=整型常数], 
... 
 标识符[=整型常数]
} 枚举变量;
 

如果枚举没有初始化, 即省掉"=整型常数"时, 则从第一个标识符开始。

例如,下面的代码定义了一个颜色枚举,变量 c 的类型为 color。最后,c 被赋值为 "blue"。

enum color { red, green, blue } c;
c = blue;

默认情况下,第一个名称的值为 0,第二个名称的值为 1,第三个名称的值为 2,以此类推。但是,您也可以给名称赋予一个特殊的值,只需要添加一个初始值即可。例如,在下面的枚举中,green 的值为 5。

enum color { red, green=5, blue };

在这里,blue 的值为 6,因为默认情况下,每个名称都会比它前面一个名称大 1,但 red 的值依然为 0。


类型转换

类型转换是将一个数据类型的值转换为另一种数据类型的值。

C++ 中有四种类型转换:静态转换、动态转换、常量转换和重新解释转换。

静态转换(Static Cast)

静态转换是将一种数据类型的值强制转换为另一种数据类型的值。

静态转换通常用于比较类型相似的对象之间的转换,例如将 int 类型转换为 float 类型。

静态转换不进行任何运行时类型检查,因此可能会导致运行时错误。

实例

inti = 10; floatf = static_cast<float>(i); // 静态将int类型转换为float类型

动态转换(Dynamic Cast)

动态转换(dynamic_cast)是 C++ 中用于在继承层次结构中进行向下转换(downcasting)的一种机制。

动态转换通常用于将一个基类指针或引用转换为派生类指针或引用。

动态转换在运行时进行类型检查。如果转换失败,对于指针类型会返回 nullptr,对于引用类型则会抛出 std::bad_cast 异常。

语法:

dynamic_cast<目标类型>(表达式)
  • 目标类型:必须是指针或引用类型。

  • 表达式:需要转换的基类指针或引用。

实例:指针类型的动态转换

#include<iostream>classBase{public: virtual ~Base() = default; // 基类必须具有虚函数}; classDerived : publicBase{public: voidshow(){std::cout << "Derived class method" << std::endl; }}; intmain(){Base* ptr_base = newDerived; // 基类指针指向派生类对象// 将基类指针转换为派生类指针Derived* ptr_derived = dynamic_cast<Derived*>(ptr_base); if(ptr_derived){ptr_derived->show(); // 成功转换,调用派生类方法}else{std::cout << "Dynamic cast failed!" << std::endl; }deleteptr_base; return0; }

输出:

Derived class method

实例:引用类型的动态转换

#include <iostream>
#include <typeinfo>

class Base {
public:
virtual ~Base() = default; // 基类必须具有虚函数
};

class Derived : public Base {
public:
void show() {
std::cout << "Derived class method" << std::endl;
}
};

int main() {
Derived derived_obj;
Base& ref_base = derived_obj; // 基类引用绑定到派生类对象

try {
// 将基类引用转换为派生类引用
Derived& ref_derived = dynamic_cast<Derived&>(ref_base);
ref_derived.show(); // 成功转换,调用派生类方法
} catch (const std::bad_cast& e) {
std::cout << "Dynamic cast failed: " << e.what() << std::endl;
}

return 0;
}

输出:

Derived class method
特性指针类型引用类型
转换失败返回值返回 nullptr抛出 std::bad_cast 异常
适用场景向下转换、运行时类型检查向下转换、运行时类型检查
性能开销较高较高
基类要求必须具有虚函数必须具有虚函数

常量转换(Const Cast)

常量转换用于将 const 类型的对象转换为非 const 类型的对象。

常量转换只能用于转换掉 const 属性,不能改变对象的类型。

实例

constinti = 10; int& r = const_cast<int&>(i); // 常量转换,将const int转换为int

重新解释转换(Reinterpret Cast)

重新解释转换将一个数据类型的值重新解释为另一个数据类型的值,通常用于在不同的数据类型之间进行转换。

重新解释转换不进行任何类型检查,因此可能会导致未定义的行为。

实例

inti = 10; floatf = reinterpret_cast<float&>(i); // 重新解释将int类型转换为float类型
AI 思考中...

12 篇笔记 写笔记

  1. #0

    公司软测的女生好凶

    hui***[email protected]

    354

    枚举实例测试:

    #include <iostream>
    using namespace std;
    int main(){
     enum days{one, two, three}day;
     day = one;
     switch(day){
     case one:
     cout << "one" << endl;
     break;
     case two:
     cout << "two" << endl;
     break;
     default:
     cout << "three" << endl;
     break;
     }
     return 0;
    }
    

    公司软测的女生好凶

    hui***[email protected]

    9年前 (2017年05月03日)
  2. #0

    000

    000***0.com

    221

    枚举类型不一定要在 main 中定义:

    #include <iostream>
    using namespace std;
    enum time 
    { 
     first,second,
     third,forth,fifth
    };
    int main()
    {
     enum time a=fifth;
     if (a==fifth) 
     {
     cout << "Succeed!";
     }
     return 0;
    }
    

    000

    000***0.com

    9年前 (2017年06月04日)
  3. #0

    风写月

    www***[email protected]

    124

    枚举和switch随便做一个判断名次的举例

    #include<iostream>
    using namespace std;
    int main()
    {
     enum rank
     {
     first,second,third
     };
     int nRank=1;
     switch (nRank)
     {
     case first:
     cout << "第一名";
     break;
     case second:
     cout << "第二名";
     break;
     case third:
     cout << "第三名";
     break;
     default:
     break;
     }
     // system("pause");
     return 0;
    }
    

    风写月

    www***[email protected]

    9年前 (2017年07月24日)
  4. #0

    knight

    106***[email protected]

    201

    关于 typedef 的几点说明:

    1. typedef 可以声明各种类型名,但不能用来定义变量。用 typedef 可以声明数组类型、字符串类型,使用比较方便。
    2. 用typedef只是对已经存在的类型增加一个类型名,而没有创造新的类型。
    3. 当在不同源文件中用到同一类型数据(尤其是像数组、指针、结构体、共用体等类型数据)时,常用 typedef 声明一些数据类型,把它们单独放在一个头文件中,然后在需要用到它们的文件中用 #include 命令把它们包含进来,以提高编程效率。
    4. 使用 typedef 有利于程序的通用与移植。有时程序会依赖于硬件特性,用 typedef 便于移植。

    knight

    106***[email protected]

    8年前 (2018年03月19日)
  5. #0

    突然的幸福

    292***[email protected]

    参考地址

    161

    size_t 在 C 语言中就有了。

    它是一种 整型 类型,里面保存的是一个整数,就像 int, long 那样。这种整数用来记录一个大小(size)。size_t 的全称应该是 size type,就是说 一种用来记录大小的数据类型

    通常我们用 sizeof(XXX) 操作,这个操作所得到的结果就是 size_t 类型。

    因为 size_t 类型的数据其实是保存了一个整数,所以它也可以做加减乘除,也可以转化为 int 并赋值给 int 类型的变量。

    类似的还有 wchar_t, ptrdiff_t

    wchar_t 就是 wide char type, 一种用来记录一个宽字符的数据类型 。

    ptrdiff_t 就是 pointer difference type, 一种用来记录两个指针之间的距离的数据类型 。

    通常,size_t 和 ptrdiff_t 都是用 typedef 来实现的。你可能在某个头文件里面找到类似的语句:

    typedef unsigned int size_t;

    而 wchar_t 则稍有不同。在一些旧的编译器中,wchar_t 也可能是用 typedef 来实现,但是新的标准中 wchar_t 已经是 C/C++ 语言的关键字,wchar_t 类型的地位已经和 char, int 的地位等同了。

    在标准 C/C++ 的语法中,只有 int float char bool 等基本的数据类型,至于 size_t, 或 size_type 都是以后的编程人员为了方便记忆所定义的一些便于理解的由基本数据类型的变体类型。

    例如:typedef int size_t; 定义了 size_t 为整型。

    int i; // 定义一个 int 类型的变量 i
    size_t size=sizeof(i); // 用 sizeof 操作得到变量i的类型的大小
    // 这是一个size_t类型的值
    // 可以用来对一个size_t类型的变量做初始化
    i=(int)size; // size_t 类型的值可以转化为 int 类型的值
    char c='a'; // c 保存了字符 a,占一个字节
    wchar_t wc=L'a'; // wc 保存了宽字符 a,占两个字节
    // 注意 'a' 表示字符 a,L'a' 表示宽字符 a
    int arr[]={1,2,3,4,5}; // 定义一个数组
    int *p1=&arr[0]; // 取得数组中元素的地址,赋值给指针
    int *p2=&arr[3];
    ptrdiff_t diff=p2-p1; // 指针的减法可以计算两个指针之间相隔的元素个数
    // 所得结果是一个 ptrdiff_t 类型
    i=(int)diff; // ptrdiff_t 类型的值可以转化为 int 类型的值

    突然的幸福

    292***[email protected]

    参考地址

    8年前 (2018年03月28日)
  6. #0

    RealRookie

    105***[email protected]

    62

    1. 每个枚举元素在声明时被分配一个整型值,默认从 0 开始,逐个加 1。

    #include <iostream>
    using namespace std;
    int main()
    {
     enum Weekend{Zero,One,Two,Three,Four};
     int a,b,c,d,e;
     a=Zero;
     b=One;
     c=Two;
     d=Three;
     e=Four;
     cout<<a<<","<<b<<","<<c<<","<<d<<","<<e<<endl;
     return 0;
    }

    2. 也可以在定义枚举类型时对枚举元素赋值,此时,赋值的枚举值为所赋的值,而其他没有赋值的枚举值在为前一个枚举值加 1。

    #include <iostream>
    using namespace std;
    int main()
    {
     enum Weekend{Zero,One,Two=555,Three,Four};
     int a,b,c,d,e;
     a=Zero;
     b=One;
     c=Two;
     d=Three;
     e=Four;
     cout<<a<<","<<b<<","<<c<<","<<d<<","<<e<<endl;
     return 0;
    }

    RealRookie

    105***[email protected]

    8年前 (2018年06月18日)
  7. #0

    Alvin

    xix***[email protected]

    290

    typedef 与 #define 的区别

    1. 执行时间不同

    关键字 typedef 在编译阶段有效,由于是在编译阶段,因此 typedef 有类型检查的功能。

    #define 则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的字符串替换,而不进行任何检查。

    【例1.1】typedef 会做相应的类型检查:

    typedef unsigned int UINT;
     
    void func()
    {
     UINT value = "abc"; // error C2440: 'initializing' : cannot convert from 'const char [4]' to 'UINT'
     cout << value << endl;
    }

    【例1.2】#define不做类型检查:

    // #define用法例子:
    #define f(x) x*x
    int main()
    {
     int a=6, b=2, c;
     c=f(a) / f(b);
     printf("%d\n", c);
     return 0;
    }

    程序的输出结果是: 36,根本原因就在于 #define 只是简单的字符串替换。

    2、功能有差异

    typedef 用来定义类型的别名,定义与平台无关的数据类型,与 struct 的结合使用等。

    #define 不只是可以为类型取别名,还可以定义常量、变量、编译开关等。

    3、作用域不同

    #define 没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用。

    而 typedef 有自己的作用域。

    【例3.1】没有作用域的限制,只要是之前预定义过就可以

    void func1()
    {
     #define HW "HelloWorld";
    }
     
    void func2()
    {
     string str = HW;
     cout << str << endl;
    }

    【例3.2】而typedef有自己的作用域

    void func1()
    {
     typedef unsigned int UINT;
    }
     
    void func2()
    {
     UINT uValue = 5;//error C2065: 'UINT' : undeclared identifier
    }

    【例3.3】

    class A
    {
     typedef unsigned int UINT;
     UINT valueA;
     A() : valueA(0){}
    };
     
    class B
    {
     UINT valueB;
     //error C2146: syntax error : missing ';' before identifier 'valueB'
     //error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    };

    上面例子在B类中使用UINT会出错,因为UINT只在类A的作用域中。此外,在类中用typedef定义的类型别名还具有相应的访问权限,【例3.4】:

    class A
    {
     typedef unsigned int UINT;
     UINT valueA;
     A() : valueA(0){}
    };
     
    void func3()
    {
     A::UINT i = 1;
     // error C2248: 'A::UINT' : cannot access private typedef declared in class 'A'
    }

    而给UINT加上public访问权限后,则可编译通过。

    【例3.5】:

    class A
    {
    public:
     typedef unsigned int UINT;
     UINT valueA;
     A() : valueA(0){}
    };
     
    void func3()
    {
     A::UINT i = 1;
     cout << i << endl;
    }

    4、对指针的操作

    二者修饰指针类型时,作用不同。

    typedef int * pint;
    #define PINT int *
     
    int i1 = 1, i2 = 2;
     
    const pint p1 = &i1; //p不可更改,p指向的内容可以更改,相当于 int * const p;
    const PINT p2 = &i2; //p可以更改,p指向的内容不能更改,相当于 const int *p;或 int const *p;
     
    pint s1, s2; //s1和s2都是int型指针
    PINT s3, s4; //相当于int * s3,s4;只有一个是指针。
     
    void TestPointer()
    {
     cout << "p1:" << p1 << " *p1:" << *p1 << endl;
     //p1 = &i2; //error C3892: 'p1' : you cannot assign to a variable that is const
     *p1 = 5;
     cout << "p1:" << p1 << " *p1:" << *p1 << endl;
     
     cout << "p2:" << p2 << " *p2:" << *p2 << endl;
     //*p2 = 10; //error C3892: 'p2' : you cannot assign to a variable that is const
     p2 = &i1;
     cout << "p2:" << p2 << " *p2:" << *p2 << endl;
    }

    结果:

    p1:00EFD094 *p1:1
    p1:00EFD094 *p1:5
    p2:00EFD098 *p2:2
    p2:00EFD094 *p2:5

    Alvin

    xix***[email protected]

    8年前 (2018年08月13日)
  8. #0

    pjs9115916

    pan***[email protected]

    60
    还可以用 typedef 来定义与平台无关的类型。

    比如定义一个叫 FALSE 的浮点类型,在目标平台一上,让它表示最高精度的类型为:

    typedef long double FALSE; 

    在不支持 long double 的平台二上,改为:

    typedef double FALSE; 

    在连 double 都不支持的平台三上,改为:

    typedef float FALSE; 

    也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。

    标准库就广泛使用了这个技巧,比如 size_t。

    另外,因为 typedef 是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。

    pjs9115916

    pan***[email protected]

    8年前 (2018年08月30日)
  9. #0

    Beta Shen

    sjg***[email protected]

    31

    有符号与无符号整数例子(注意,测试平台为ubuntu 14.04 32位,gcc 4.8)

    #include <iostream>
    using namespace std;
    int main()
    {
     int n = 0;
     n--;
     unsigned int u = (unsigned int)n;
     unsigned long long int v = (unsigned long long int)n;
     cout << "Unsigned int value for " << n << " is " << u << "(0x"
     << hex << u << ")" << endl;
     cout << "0x" << u << " increase 1 is " << (u+1) << endl;
     cout << "Unsigned long long int value for " << dec << n << " is " << v << "(0x"
     << hex << v << ")" << endl;
     cout << "0x" << v << " increase 1 is " << (v+1) << endl;
    }

    输出结果如下:

    Unsigned int value for -1 is 4294967295(0xffffffff)
    0xffffffff increase 1 is 0
    Unsigned long long int value for -1 is 18446744073709551615(0xffffffffffffffff)
    0xffffffffffffffff increase 1 is 0

    Beta Shen

    sjg***[email protected]

    7年前 (2019年03月29日)
  10. #0

    Mars.CN

    suo***[email protected]

    91

    为了方便枚举的使用,应该和 typedef 结合使用,例如:

    typedef enum BAYER_PATTERN{
     BAYER_RG=0,
     BAYER_BG,
     BAYER_GR,
     BAYER_GB
    }BAYER_PATTERN;

    使用的时候就不用再 enum BAYER_PATTERN color = BAYER_RG; 了,而可以直接用:

    BAYER_PATTERN color = BAYER_RG;

    Mars.CN

    suo***[email protected]

    7年前 (2019年11月13日)
  11. #0

    万能的木头君

    inc***[email protected]

    71

    可以使用 typedef 为类型添加別名:

    typedef int Int;

    当然,也可以使用 using:

    using Int=int;

    可以看到,第二种可读性更高。

    另外,using 在模板环境中会更加强大。

    假设有一个模板参数是 int 的类 grid,那么可以这么做:

    using grid1=grid<1>;

    那要声明一个指向返回 void,有一个 int 参数的函数的函数指针呢?

    或许可以使用 typedef:

    typedef void(*f1)(int);

    可以看到,可读性很低,那使用 using 呢?

    using f1=void(*)(int);

    使用 using 明显更好理解:

    所以,始终优先使用 using。

    那如果将函数指针作参数呢?

    void func(void(*f1)(int)){
    //...
    }

    这无法使用 using 完成。

    但是,使用 <functional> 中的 function 可以更好地完成任务:
    void func(function<void(int)>f1){
    //...
    }

    所以,尽量不去使用 typedef

    万能的木头君

    inc***[email protected]

    6年前 (2020年12月12日)
  12. #0

    clara

    137***[email protected]

    19

    reinterpret_caststatic_cast 都是 C++ 中的类型转换运算符,但它们在用途和安全性上有显著的区别。

    1、reinterpret_cast

    reinterpret_cast 用于在几乎任意类型之间进行低级别、几乎没有类型检查的转换。这种转换是直接按位重新解释数据,所以它是最不安全的一种转换。通常用于:

    • 将指针类型转换为其他指针类型。
    • 将指针转换为足够大的整数类型,反之亦然。
    • 在不同类型的对象之间进行低级别转换。

    这种转换不进行任何检查,所以程序员必须确保这种转换是合理的和安全的。

    2、static_cast

    static_cast 用于在相关类型之间进行类型转换,相对安全并且经过编译时类型检查。适用于:

    • 基本类型之间的转换,例如从 intfloat
    • 指针和引用在相关类层次结构中的上行和下行转换。
    • 通过普通指针和引用转换为 void*,反之亦然。

    clara

    137***[email protected]

    2年前 (2024年05月24日)

点我分享笔记

  • 昵称 (必填)
  • 邮箱 (必填)
  • 引用地址

AltStyle によって変換されたページ (->オリジナル) /