实用电子商务网站建立,特产网站建设策划书,同ip网站做排名seo,重庆网站建设外贸目录 一、const
二、static
三、#define 和 typedef
四、#define 和 inline
五、#define 和 const
六、new 和 malloc
七、const 和 constexpr
八、volatile
九、extern
十、前置 和后置
十一、atomic
十二、struct 和 class 一、const
1、const 关键字可用于定义…目录 一、const
二、static
三、#define 和 typedef
四、#define 和 inline
五、#define 和 const
六、new 和 malloc
七、const 和 constexpr
八、volatile
九、extern
十、前置 和后置
十一、atomic
十二、struct 和 class 一、const
1、const 关键字可用于定义常量一旦被赋值其值在程序运行期间就不能被修改。
const int num 10; // 定义一个常量 num值为 102、const 用来修饰指针时有两种用法 1const 数据类型 *指针变量 变量名 or 数据类型 const *指针变量 变量名 当const在*前时指的是不能通过这个指针变量来修改其指向的值而指针本身可被修改 int temp 10 b 1;
const int* a temp;
int const *a temp;
// 更改
*a 9; // 错误只读对象
temp 9; // 正确
a b; //正确 2数据类型 * const 指针变量 变量名 当const在*后时指的是指针本身不可被修改但可以通过指针修改其指向的值 int temp 10;
int temp1 12;
int* const p temp;
// 更改
p temp2; // 错误
*p 9; // 正确 3、const 可用来修饰引用表示不能通过该引用修改变量
int temp 10;
const int t temp;
temp 9; // 正确
t 9; //错误
其中const权限只可降级即非const引用或非const值可以初始化const引用而反过来不行
int temp1 10;
const int temp2 5;
int a temp1;
const int b a; //正确
int c b; //错误const权限不可升级
int d temp2; //错误const权限不可升级
4、const修饰成员函数和实例对象
当一个成员函数被 const 修饰时它表明这个函数不会修改类的成员变量但可以修改类的静态成员变量因为静态成员变量不属于对象本身而是属于整个类的是所有对象共享一个的。当一个对象被 const 修饰后意味着这个对象在生命周期内的成员属性不可改变故该对象只能调用 const 成员函数。
#include iostreamclass MyClass {
private:int nonStaticValue;
public:static int staticValue;MyClass(int v) : nonStaticValue(v) {}int getNonStaticValue() const { // const 成员函数return nonStaticValue;}void modifyStaticValue(int v) const { // const 成员函数修改静态成员变量staticValue v;}
};int MyClass::staticValue 0; // 静态成员变量初始化int main() {const MyClass obj(10); // 创建 const 对象std::cout obj.getNonStaticValue() std::endl; // 可以调用 const 成员函数获取非静态成员变量的值obj.modifyStaticValue(20); // const 成员函数可以修改静态成员变量std::cout MyClass::staticValue std::endl; // 输出修改后的静态成员变量的值return 0;
} 二、static
1、在函数内部static 修饰的变量其生存期贯穿整个程序运行期间但作用域仍在函数内部。
void func() {static int count 0; // 每次调用 func 函数count 的值都会保留count;
}2、在类中static 成员变量属于整个类而非某个对象。
class MyClass {
public:static int staticVar;
};int MyClass::staticVar 0;3、如果static修饰了全局变量生命周期不变还是全局但是作用域降为了本文件有效修饰全局函数是同样的道理
#include iostream// 定义全局变量
static int globalStaticVar 10; // 使用 static 修饰的全局变量void function() {std::cout globalStaticVar in function: globalStaticVar std::endl;
}int main() {std::cout globalStaticVar in main: globalStaticVar std::endl;function();// 错误在其他文件中无法访问这个 static 修饰的全局变量// extern int globalStaticVar; return 0;
}
4、static修饰成员函数不与特定的对象相关联可以通过类名和作用域解析运算符直接调用虽然仍然可以使用实例化对象调用静态成员函数但在实际编程中不推荐这样的写法因为静态成员函数不依赖于具体的对象实例它是属于整个类的。通常更推荐使用类名直接来调用静态成员函数如下所示
MyClass::staticMethod(); 三、#define 和 typedef
在 C 和 C 中#define 和 typedef 都可以用于给类型取别名但它们之间存在一些重要的区别。 1、语法和实现机制 #define 是预处理器指令通过简单的文本替换来实现别名定义。 #define INT_PTR int*typedef 则是在编译阶段起作用的关键字。 typedef int* IntPtr;2、作用域 #define 不受作用域限制在预处理器阶段进行替换全局有效typedef 遵循作用域规则在其定义的作用域内有效。 3、类型检查 #define 只是简单的文本替换没有类型检查。typedef 是类型定义具有类型检查。 4、复杂类型处理 对于复杂的类型如指针、数组等typedef 更清晰和直观。例如对于指向函数的指针使用 typedef 更易理解。 typedef int (*FuncPtr)(int);#define 在处理复杂类型时可能会导致混淆和错误。 5、可移植性 typedef 的行为在不同的编译器中通常更一致具有更好的可移植性。 总的来说虽然 #define 和 typedef 都能给类型取别名但在大多数情况下特别是对于复杂类型和需要类型检查及良好可移植性的场景typedef 是更推荐的选择。 四、#define 和 inline
在 C/C 中inline 函数和宏函数都有在代码中进行内联展开以提高性能的作用但它们之间存在一些显著的区别。 1、语法和定义方式 inline 函数是使用 inline 关键字修饰的正常函数。 inline int add(int a, int b) {return a b;
}宏函数则是通过 #define 宏定义来实现的只是在预处理阶段简单的文本替换 #define ADD(a, b) ((a) (b))2、类型检查 inline 函数具有严格的类型检查参数类型必须匹配。宏函数只是简单的文本替换不进行类型检查可能会导致潜在的类型错误。 3、参数处理 inline 函数对参数的处理是按照函数的参数传递规则进行的。宏函数如果定义不当可能会出现不符合预期的情况例如 #define SQUARE(x) (x * x)
int a 2 3;
int b SQUARE(a); // 会被替换为 (2 3) * 2 3)结果不符合预期//正确定义
#define SQUARE(x) ((x) * (x))4、调试 inline 函数可以像普通函数一样进行调试可以设置断点、查看调用栈等。宏函数在调试时可能会带来困难因为它们在预处理阶段就被替换了。 5、代码可读性 inline 函数的定义方式更符合函数的常规语法代码可读性更好。宏函数的定义可能会使代码看起来比较复杂可读性较差。 在大多数情况下inline 函数由于具有更好的类型安全性、可读性和调试性是更优的选择。然而在一些简单且性能关键的场景中宏函数可能仍然有用。最后一点就是inline只是对编译器的建议具体做不做内联要看编译器的选择。
五、#define 和 const
const和#dfine都可以用来定义常量#define只是对字面量的文本替换没有类型检查预处理器在替换时也不会考虑作用域const定义的常量是在编译时要进行类型检查的
#define PI 3.14159
const double Pi 3.14159;
六、new 和 malloc
1、new内存分配失败时会抛出bac_alloc异常它不会返回NULLmalloc分配内存失败时返回NULL。
2、使⽤new操作符申请内存分配时⽆须指定内存块的⼤⼩⽽malloc则需要显式地指出所需内存的尺⼨。
3、opeartor new /operator delete可以被重载⽽malloc/free并不允许重载。
4、new/delete会调⽤对象的构造函数/析构函数以完成对象的构造/析构。⽽malloc/free则不会
5、malloc与free是C/C语⾔的标准库函数,new/delete是C的运算符
6、new会返回申请类型的指针malloc是返回void*指针需要强制转换 七、const 和 constexpr
const 和 constexpr 都用于定义常量const 的值可以在运行时确定而 constexpr 的值必须在编译时确定。constexpr 对值的确定时间有更严格的要求并且在一些特定的场景中能提供更好的性能和代码可读性。
八、volatile
volatile 用于告诉编译器该变量的值可能会被意外地改变不要进行 volatile修饰的变量旨在告诉编译器关闭对这个变量的编译优化当需要对改变了进行读写和运算时必须从内存重新装载内容而不允许读取寄存器中的缓存。
九、extern
extern 用于声明一个在其他文件中定义的全局变量或函数。
十、前置 和后置 前置返回已经修改过的对象本身而后置返回被修改之前的临时对象所以后置的表达式不能作为左值但前置可以
int num 6;
int preIncrement num; // 返回7
int postIncrement num; // 返回 6
十一、atomic
atomic 用于实现原子操作确保在多线程环境中的操作是原子性的不会被其他线程打断。 定义 atomic 通常用于多线程编程中用于确保对特定类型的操作是原子性的。 用途 保证操作的原子性在多线程环境下原子操作可以避免数据竞争和不一致性。例如对一个整数的递增或读取操作如果使用 atomic 类型包装就能保证在多线程并发访问时不会出现中间状态的错误。 示例 #include atomic// 定义一个原子整数
std::atomicint atomicVar(0); //C17支持初始化void threadFunction() {atomicVar; // 原子性的递增操作
}int main() {// 创建多个线程执行 threadFunctionreturn 0;
}注意事项 并非所有的操作都能被原子化具体取决于所使用的原子类型和编译器的支持。使用 atomic 虽然能保证原子性但可能会带来一定的性能开销。 总之atomic 是多线程编程中的重要工具能有效地提高程序在多线程环境下的正确性和稳定性但需要在性能和正确性之间进行权衡。
十二、struct 和 class
在 C 语言中struct 主要用于简单地将不同类型的数据组合在一起形成一个新的数据类型。其成员均为公开的并且 struct 本身无法包含成员函数仅仅是纯粹的数据组合。
在 C 中struct 得到了显著的提升实际上被视为类的一种形式。尽管 struct 的成员默认访问权限为 public但它也能够像 class 一样显式地指定成员的访问权限为私有或受保护。并且struct 还可以在其内部声明成员函数从而实现更为复杂的行为和操作。
以下是 C 中 struct 包含成员函数的示例
struct Student {std::string name;int age;void displayInfo() { // 成员函数std::cout Name: name , Age: age std::endl;}
};基于上述特性在实际编程中建议采取以下最佳实践
对于仅仅是数据的简单组合且希望成员默认具有公共访问权限的情况使用 struct 是一个不错的选择。例如当定义一些纯粹用于数据传递或存储的结构体时struct 能够清晰地表达数据的结构并且方便数据的访问和操作。
当面对更为复杂的对象涉及到数据的封装、隐藏以及更丰富的行为和操作时使用 class 进行定义会更为合适。通过将成员设置为私有并提供公共的接口函数来控制对象的状态和行为可以更好地实现面向对象编程中的封装和信息隐藏原则增强代码的健壮性、可维护性和可扩展性。