网站网站建设网页设计,在网站上做宣传属于广告费用吗,wordpress 导入工具插件,安徽省建设监理协会 旧网站文章目录 1.final和override关键字2.extern C的用法3.野指针和垂悬指针(悬空指针)4.指针指向的内存被释放是什么意思5.C和C的类型安全6.C中的重载、重写#xff08;覆盖#xff09;和隐藏的区别 1.final和override关键字
final和override是C11引入的关键字… 文章目录 1.final和override关键字2.extern C的用法3.野指针和垂悬指针(悬空指针)4.指针指向的内存被释放是什么意思5.C和C的类型安全6.C中的重载、重写覆盖和隐藏的区别 1.final和override关键字
final和override是C11引入的关键字用于在类的继承和虚函数重写中进行特定的语义声明 final final关键字用于修饰类、成员函数或虚函数表示它们是最终版本不允许被继承、重写或覆盖 用于修饰类时表示该类的最终类不能被其他类继承 用于修饰成员函数时表示该成员函数是最终版本不能被子类的同名函数重写或覆盖。 class Base {public:virtual void foo() final; // 声明foo()是最终版本不允许子类重写};class Derived : public Base {public:// 试图重写foo()但由于在Base中声明为final将会产生编译错误// void foo() override; // 错误不能重写final函数};override override关键字用于修饰派生类中覆盖基类的虚函数用于明确标识该函数是对基类虚函数的覆盖实现提高代码的可读性和安全性 使用override关键字可以确保子类中的虚函数命名和基类中的虚函数一致防止由于命名不一致而导致的意外。 class Base {public:virtual void foo();};class Derived : public Base {public:void foo() override; // 明确标识对基类虚函数foo()的覆盖}; 总之final关键字用于阻止类或成员函数的继承或重写而override关键字用于明确标识派生类中对基类虚函数的覆盖实现。这两个关键字都提高了代码的安全性和可读性并在面向对象编程中起到重要的作用。 2.extern C的用法 extern “C” 是C中用于处理C语言和C语言混合编程的关键字在C中有时候需要与C语言的代码进行链接或者在C中调用C语言编写的函数此时就可以使用extern “C” 来声明C语言的函数接口 当使用extern “C” 声明函数时C编译器会按照C语言的命名规则来处理该规则这样可以确保C和C的函数名在链接时保持一致避免了由于C的函数重载等特性导致的函数名修饰不一致的问题 假设有以下 C 语言的头文件 functions.h // functions.h#ifndef FUNCTIONS_H#define FUNCTIONS_Hint add(int a, int b);#endif // FUNCTIONS_H对应的 C 语言源文件 functions.c 实现了该头文件中的函数 // functions.c#include functions.hint add(int a, int b) {return a b;}现在我们在 C 代码中想要调用 add 函数可以在 C 文件中这样声明 // main.cpp#include iostream#include functions.hextern C {#include functions.h // 使用 extern C 包裹 include 指令}int main() {int result add(5, 10);std::cout Result: result std::endl;return 0;}总结extern C 用于在 C 中处理 C 语言的函数接口保证函数名在链接时的一致性从而实现 C 和 C 的混合编程。这在与 C 语言编写的库或代码进行交互时非常有用。
3.野指针和垂悬指针(悬空指针) 野指针是指指针指向的内存地址是无效的即指针没有被正确初始化或者指针指向的内存已经被释放但指针本身还保留着原来的地址。 当我们使用野指针时由于其指向的内存可能已经被其他程序或系统回收所以访问该指针指向的内存会导致不可预测的行为可能会导致程序崩溃或产生错误的结果 野指针的产生通常是由于以下原因 1.未初始化指针指针变量在定义后没有被正确初始化它的值是随机的可能指向任意内存地址指针指向已释放的内存在使用delete或free释放内存后没有将指针置为nullptr int* ptr new int;delete ptr; // 释放内存后ptr 成为野指针应该将 ptr 置为 nullptrptr nullptr;指针误用指针被错误的修改导致它指向了无效的内存地址 int arr[5] {1, 2, 3, 4, 5};int* ptr arr[0];ptr 10; // ptr被错误地修改指向了不属于arr的内存地址ptr成为野指针要避免使用野指针我们要养成良好的编程习惯确保指针在定义后都被正确初始化并在释放指针指向的内存后立即将指针置为nullptr。同时不要随意修改指针的值以防止野指针的产生 垂悬指针是指指针指向的内存已经被释放或释放后没有及时置空导致指针的值仍然是之前指向的地址但该地址的内容可能已经无效。当我们使用垂悬指针时由于其指向的内存已经无效访问该指针指向的内存会导致未定义行为可能会产生不可预测的结果。 垂悬指针通常是由于以下原因产生 释放后未置空在使用 delete 或 free 释放内存后没有将指针置为 nullptr int* ptr new int;delete ptr; // 释放内存后ptr 成为垂悬指针应该将 ptr 置为 nullptrptr nullptr;引用悬挂当指针指向一个引用而该引用的生命周期已经结束指针就会成为垂悬指针。 int a 10;int ref a;int* ptr ref; // ptr 指向引用 ref如果在之后 ref 的生命周期结束ptr 就会成为垂悬指针函数返回局部变量地址在函数内部定义了一个局部变量并返回其地址但在函数结束后该局部变量的内存已经被释放。
要避免使用垂悬指针我们应该养成良好的编程习惯在释放指针指向的内存后立即将指针置为 nullptr。同时在返回局部变量的指针时应该确保返回的是有效的动态内存分配堆内存或者静态存储区全局变量或静态变量的地址。
4.指针指向的内存被释放是什么意思 释放内存意味着该内存不再属于当前程序系统可以重新分配给其他程序使用。 5.C和C的类型安全 类型安全是指编程语言或程序设计中的一种属性确保在程序执行过程中不会发生不合法或未定义的类型操作类型安全很大程度上可以等价于内存安全类型安全的代码不会试图访问自己没被授权的内存区域。类型安全保证了以下几点 类型检查在编译或运行时编程语言会对类型进行检查防止不同类型之间的非法操作类型转换的明确性在进行类型转换时必须明确指定避免隐式的不明确转换从而降低类型错误的概率类型兼容性确保只有合法的类型转换才能进行防止发生未定义行为或错误的结果内存安全性防止越界访问、空指针引用等导致的内存错误从而提高程序的稳定性和安全性 C的类型安全性 C是一种弱类型语言类型的转换相对灵活可以进行隐式类型转化这使得C中存在潜在的类型错误和未定义行为C编译器在类型检查方面较弱无法在编译时完全捕获所有类型错误可能会导致在运行时出现错误 以下是常见的例子 printf格式输出 int main() {printf(int类型输出:%d\n, 10);printf(float类型输出:%f\n, 10);return 0;
}执行结果 int类型输出:10
float类型输出:0.000000malloc函数的返回值 malloc是C语言中用来进行内存分配的函数它的返回类型是void* 我们经常对结果进行类型转换 char* pstr(char* )malloc(100*sizeof(char))我们进行了显式类型转换将void *类型转换为了char * 类型sizeof的参数类型和显式转换的类型匹配的话就没什么问题但是如果不匹配就很可能带来一些问题如int * pstr(int * )malloc(100 * sizeof(char))而这样的转换C并不会提示错误。 C的类型安全性 C是一种静态类型语言类型检查在编译时进行所有类型的转换必须显式指定除了一些隐式类型转换如派生类向基类的指针转换 C 提供了更强大的类型系统包括强制类型转换static_cast、dynamic_cast、reinterpret_cast、const_cast来明确指定类型转换以及运算符重载来定义特定类型之间的操作。
6.C中的重载、重写覆盖和隐藏的区别 重载 重载是指在同一个作用域内函数名相同但参数列表不同的情况下可以定义多个具有相同函数名但参数个数或类型不同的函数。 重载函数可以根据不同的参数来执行相似的操作提高代码的复用性和可读性 重载函数在编译时通过参数个数、类型和顺序来决定调用哪个函数 class Math {public:int add(int a, int b);double add(double a, double b);};重写/覆盖override 重写是指派生类重新定义基类中的虚函数 重写虚函数允许子类为基类的虚函数提供自己的实现从而实现多态性 重写发生在类之间的继承关系中子类函数与父类函数具有相同的函数名、参数列表和返回类型并且基类函数必须声明为虚函数 class Shape {public:virtual void draw() {std::cout Drawing a shape. std::endl;}};class Circle : public Shape {public:void draw() override {std::cout Drawing a circle. std::endl;}};重载和重写的区别 重写是父类和子类之间的垂直关系重载是不同函数之间的水平关系重写要求参数列表相同重载则要求参数列表不同返回值不要求重写关系中调用方法根据对象类型决定重载根据调用时实参与形参的对应关系来选择函数体 隐藏 隐藏是指在派生类中定义了一个与基类中同名但不具有虚函数特性的函数这样它就会隐藏基类中的同名函数包括以下情况 两个函数参数相同但是基类函数不是虚函数。如果基类函数是虚函数则就是重写了。 //父类class A{public:void fun(int a){cout A中的fun函数 endl;}};//子类class B : public A{public://隐藏父类的fun函数void fun(int a){cout B中的fun函数 endl;}};int main(){B b;b.fun(2); //调用的是B中的fun函数b.A::fun(2); //调用A中fun函数return 0;}两个函数参数不同则无论基类函数是否是虚函数都会被隐藏。和重载的区别在于两个函数不在同一个类中。 //父类class A {public:virtual void fun(int a) {cout A中的fun函数 endl;}};//子类class B : public A {public://隐藏父类的fun函数virtual void fun(char* a) {cout A中的fun函数 endl;}};int main() {B b;b.fun(2); //报错调用的是B中的fun函数参数类型不对b.A::fun(2); //调用A中fun函数return 0;}基类指针指向派生类对象时基类指针可以直接调用到派生类的覆盖函数也可以通过 :: 调用基类被覆盖的虚函数而基类指针只能调用基类的被隐藏函数无法识别派生类中的隐藏函数。