C++中常用关键字详解(3)

2023-08-08 16:22:52 来源:Linux兵工厂

位域

C++中,位域(bit fields)是一种特殊的数据结构,允许将结构体或类的成员变量按位进行分配。通过位域,可以有效地利用内存,节省存储空间,特别适用于表示布尔类型、标志位或其他不需要完整字节的数据。


(资料图)

位域的语法格式如下:

struct MyStruct {    dataType memberName : numBits;};

其中,dataType是要存储的数据类型,memberName是位域成员的名称,numBits是分配给该成员的位数。numBits表示该成员所占用的位数,必须是正整数,不能超过数据类型的位数。

以下是一个简单的例子,演示了C++类中位域的使用:

#include < iostream >class MyFlags {public:    MyFlags() : isRed(0), isGreen(0), isBlue(0) {}    // 位域成员    unsigned int isRed : 1;    unsigned int isGreen : 1;    unsigned int isBlue : 1;};int main() {    MyFlags myFlags;    myFlags.isRed = 1;    myFlags.isGreen = 0;    myFlags.isBlue = 1;    std::cout < < "Size of MyFlags: " < < sizeof(MyFlags) < < " bytes" < < std::endl;    std::cout < < "isRed: " < < myFlags.isRed < < std::endl;    std::cout < < "isGreen: " < < myFlags.isGreen < < std::endl;    std::cout < < "isBlue: " < < myFlags.isBlue < < std::endl;    return 0;}

输出可能为:

Size of MyFlags: 4 bytesisRed: 1isGreen: 0isBlue: 1

在上述示例中,我们定义了一个名为MyFlags的类,其中包含三个位域成员isRed、isGreen和isBlue,每个成员都占用1位。由于unsigned int通常是4字节(32位),所以类MyFlags的大小为4字节。

在使用类中的位域时,需要注意类的成员访问权限以及可能的内存对齐问题。位域成员只能是整数类型或枚举类型,并且不支持引用。类中的位域成员也受到相同的限制,不能超过其数据类型的位数。

使用位域时应该谨慎考虑,确保了解位域的特性和限制,并在适当的情况下使用它们,以提高内存利用效率。在需要移植性和可靠性的场景中,建议使用常规的数据成员而不是位域

extern “C”

在C++中,extern "C"是一个用于声明C语言风格的函数和变量的关键字。C++与C在编译和链接过程中有一些差异,其中包括名称修饰(name mangling)和函数重载等特性。使用extern "C"可以告诉C++编译器将某些函数和变量按照C语言的规则进行处理,以实现C和C++之间的混合编程

使用extern "C"有以下几个常见的场景:

C++调用C语言库:当C++代码需要调用一个由C语言编写的库时,由于C和C++之间的名称修饰不同,需要使用extern "C"来正确链接C语言的函数。C语言调用C++函数:当C语言代码需要调用一个由C++编写的函数时,由于C++可能存在函数重载和其他特性,需要使用extern "C"来告诉C语言编译器按照C语言的方式处理函数。

以下是一些示例,说明了extern "C"的用法:

C++调用C语言库的示例:C++代码(main.cpp):

#include < iostream >extern "C" {    void c_function(); // 声明C语言风格的函数}int main() {    c_function(); // 调用C语言风格的函数    return 0;}

C语言代码(c_library.c):

#include < stdio.h >void c_function() {    printf("This is a C function.n");}

C语言调用C++函数的示例: C++代码(cpp_library.cpp):

#include < iostream >extern "C" {    void cpp_function(); // 声明C语言风格的函数}void cpp_function() {    std::cout < < "This is a C++ function." < < std::endl;}

C语言代码(main.c):

extern void cpp_function(); // 声明C语言风格的函数int main() {    cpp_function(); // 调用C++函数    return 0;}

在上述示例中,我们通过使用extern "C"关键字来正确地链接C和C++之间的函数。

需要注意的是,extern "C"应该只用于C和C++之间的函数和全局变量的声明,而不应该用于类的定义和成员函数。因为类的成员函数涉及到C++的特性,无法通过简单的名称修饰解决链接问题。在需要使用C++类的情况下,可以考虑提供一个纯C接口来实现交互。

struct

在C++中,struct是用于定义自定义数据类型的关键字,它是一种用户定义的数据结构,可以包含不同类型的成员变量和成员函数。struct与class非常相似,但有一些不同之处。

以下是关于C++中struct的一些详解:

成员变量:struct可以包含不同类型的成员变量,这些成员变量默认是public(公共)访问权限的。这意味着结构体的成员可以从外部直接访问和修改。
struct MyStruct {     int x;  // 公共成员变量,默认访问权限是 public     double y; // 公共成员变量,默认访问权限是 public};
成员函数:struct可以定义成员函数,用于操作和访问结构体的成员变量。
struct MyStruct {    int x;    void printX()     {        std::cout < < "x = " < < x < < std::endl;    }};
继承:struct可以通过继承派生出子结构体。派生类继承了基类的成员和方法。
struct Base  {     int x; }; struct Derived : Base  {     double y; };
构造函数和析构函数:struct可以定义构造函数和析构函数,用于对象的初始化和资源的清理。
struct MyStruct {     int x;     // 构造函数     MyStruct(int value)      {         x = value;     }     // 析构函数     ~MyStruct()      {         std::cout < < "MyStruct object destroyed." < < std::endl;     } };
类型别名:struct可以使用typedef来定义类型别名。
struct MyStruct {    typedef int MyInt; // 定义类型别名 MyInt    MyInt x;};

需要注意的是,尽管struct和class都可以用来定义自定义数据类型,但它们有一些细微的差别:

在struct中,默认的成员访问权限是 public,而在class中,默认的成员访问权限是 private。对于结构体,默认继承权限是 public,而对于类,默认继承权限是 private。在语法上,类可以使用class关键字或struct关键字来定义,而struct只能用于定义结构体。除了默认的访问权限和默认继承权限之外,struct和class在其他方面几乎是相同的。使用哪个关键字取决于编程风格和设计选择。

union

在C++中,union是一种特殊的数据结构,允许在相同的内存位置存储不同的数据类型。union的所有成员共享相同的内存空间,这使得union在一些特定情况下非常有用,例如节省内存或进行类型转换。

union的语法如下:

union UnionName {    dataType member1;    dataType member2;};

其中,UnionName是union的名称,dataType是要存储在union中的数据类型。union的成员可以是不同类型的变量,但是所有成员共享同一块内存,只有一个成员可以被赋值。在任何时候,union中只有一个成员的值是有效的,而其他成员的值将是未定义的。

以下是一个简单的示例,演示了union的用法:

#include < iostream >union MyUnion {    int intValue;    double doubleValue;    char charValue;};int main() {    MyUnion u;    u.intValue = 42;    std::cout < < "intValue: " < < u.intValue < < std::endl;    u.doubleValue = 3.14;    std::cout < < "doubleValue: " < < u.doubleValue < < std::endl;    u.charValue = "A";    std::cout < < "charValue: " < < u.charValue < < std::endl;    // 输出最后设置的成员值    std::cout < < "intValue after charValue assignment: " < < u.intValue < < std::endl;    return 0;}

输出可能为:

intValue: 42doubleValue: 3.14charValue: AintValue after charValue assignment: 65

在上述示例中,我们定义了一个union MyUnion,它有三个成员intValue、doubleValue和charValue,分别是int、double和char类型。我们可以在不同的时间点给union的不同成员赋值。由于union的成员共享同一块内存,最后赋值的成员的值会覆盖之前的值。

C++中除此之外的特性还有:

默认访问控制符为 public可以含有构造函数、析构函数不能含有引用类型的成员不能继承自其他类,不能作为基类不能含有虚函数匿名 union 在定义所在作用域可直接访问 union 成员匿名 union 不能包含 protected 成员或 private 成员全局匿名联合必须是静态(static)的
#include< iostream >union UnionTest {    UnionTest() : i(1) {};    int i;    double j;};static union {    int i;    double j;};int main() {    UnionTest u;    union     {        int i;        double j;    };    std::cout < < u.i < < std::endl; // 输出 UnionTest 联合的 1    ::i = 2;    std::cout < < ::i < < std::endl; // 输出全局静态匿名联合的 2    i = 3;    std::cout < < i < < std::endl; // 输出局部匿名联合的 3    return 0;}

需要特别注意的是,使用union需要非常小心,因为它的行为容易导致难以预料的结果。由于union没有记录当前存储的数据类型,所以在使用时需要确保正确理解其成员的含义,并避免出现未定义行为。一般来说,union应该在需要特殊的内存布局和节省内存时才使用,并且应该小心处理其中的数据。在现代C++编程中,更倾向于使用std::variant或std::any等类型安全的替代方案。

标签:

上一篇:开关电源的工作原理 反激式转换器和正激式转换器讲解
下一篇:最后一页