综述
参考 https://en.cppreference.com/w/
详细内容
- C++虚拟析构函数
当类会派生出子类时,析构函数必须是虚函数,否则子类对象在销毁时不会释放父类资源。
class ParentA { public: ParentA(){} virtual ~ParentA(){} // other functions } class SonAOfParentA:public ParentA { public: SonAOfParentA(){} ~SonAOfParentA(){} // other functions }
typeid
是操作符,用于获取对象类名
运行时获知变量类型名称,可以使用typeid(变量).name()
,需要注意不是所有编译器都
输出"int"、"float"
等之类的名称,对于这类的编译器可以这样使用:float f = 1.1f; if(typeid(f) == typeid(0.0f) ) ……
补充:对非引用类型,typeid是在编译时期识别的,只有引用类型才会在运行时识别。
#include <iostream> #include <typeinfo> using namespace std; int main(void) { // sample 1 cout << typeid(1.1f).name() << endl; // sample 2 class Base1 {}; class Derive1:public Base1 {}; Derive1 d1; Base1& b1 = d1; cout << typeid(b1).name() << endl; // 输出"class Base1",因为Derive1和Base1之间没有多态性 // sample 3, 编译时需要加参数 /GR class Base2 { virtual void fun( void ) {} }; class Derive2:public Base2 { }; Derive2 d2; Base2& b2 = d2; cout << typeid(b2).name() << endl; // 输出"class Derive2",因为Derive1和Base1之间有了多态性 // sample 4 class Derive22:public Base2 { }; // 指针强制转化失败后可以比较指针是否为零,而引用却没办法,所以引用制转化失败后抛出异常 Derive2* pb1 = dynamic_cast<Derive2*>(&b2); cout << boolalpha << (0!=pb1) << endl; // 输出"true",因为b2本身确实是指向Derive2 Derive22* pb2 = dynamic_cast<Derive22*>(&b2); cout << boolalpha << (0!=pb2) << endl; // 输出"false",因为b2本身不是指向Derive22 try { Derive2& rb1 = dynamic_cast<Derive2&>(b2); cout << "true" << endl; }catch( bad_cast ) { cout << "false" << endl; } try{ Derive22& rb2 = dynamic_cast<Derive22&>(b2); cout << "true" << endl; } catch( ... ) // 应该是 bad_cast,但不知道为什么在VC++6.0中却不行?因为VC++6.0默认状态是禁用 RTTI 的,启用方式:project->setting->c/c++->category->c++ Language 下面第二个复选框选中。 { cout << "false" << endl; } return 0; }
vs工程不同版本升级
在将应用程序升级至 Visual Studio 的新版本时,建议升级应用程序链接到的所有库和 DLL,
而且这在许多情况下是必要的。 这要求你拥有访问源代码的权限,或库供应商能提供使用相同的
主版本编译器进行编译的新二进制文件。 若下列条件之一为 true,则可跳过此部分,此部分介
绍有关二进制兼容性的详细信息。 如果不属于任一情况,则可能无法在已升级的应用程序中使用库。
此部分的信息将帮助你了解是否可以继续进行升级。
.obj 和 .lib 文件格式都定义完善且很少更改。 有时会对这些文件格式进行添加,但这些添加通
常不会影响较新工具集使用由较旧工具集生成的对象文件和库的能力。 但如果使用 /GL(全程序优化)
进行编译,则是大型例外情况。 如果使用 /GL 进行编译,则生成的对象文件只能使用生成它时所用的同
一工具集进行链接。 因此,如果使用 /GL 和 Visual Studio 2017 (v141) 编译器生成对象文件,则
必须使用 Visual Studio 2017 (v141) 链接器对其进行链接。 这是由于对象文件中的内部数据结构在
工具集各主版本之间不稳定,且较新的工具集无法识别较旧的数据格式。
C++ 不具备稳定的应用程序二进制接口 (ABI)。 但是,Visual Studio 为版本的所有次要版本维护稳定的
C++ ABI。 Visual Studio 2015 (v140)、Visual Studio 2017 (v141) 和 Visual Studio 2019 (v142)
仅次要版本有所不同。 它们都具有相同的主版本号,即 14。 有关详细信息,请参阅 Visual Studio 2015
和 Visual Studio 2019 之间的 C++ 二进制兼容性。
如果对象文件具有包含 C++ 链接的外部符号,则该对象文件可能无法与其他主版本工具集生成的对象文件正确链接。
有许多可能的结果:链接可能会完全失败(例如,如果名称修饰已更改)。 链接可能会成功,但对象在运行时可能
无法正常工作(例如,如果类型布局已更改)。 或在许多情况下,对象可能碰巧能够正常工作并且不会出现任何错误。
另请注意,尽管 C++ ABI 不稳定,但 COM 所需的 C ABI 和 C++ ABI 子集是稳定的。
如果链接到导入库,保留 ABI 兼容性的 Visual Studio 可再发行库的更高版本可在运行时使用。 例如
,如果使用 Visual Studio 2015 Update 3 工具集编译和链接应用,则可使用任何 Visual Studio
2017 或 Visual Studio 2019 可再发行库,因为 2015、2017 和 2019 库具有保留的二进制后向兼容性。
反之则不然:不能将可再发行库用于版本低于之前生成代码所使用的工具集版本的早期版本,即使其具有可
兼容的 ABI 也是如此。
如果使用 Visual Studio C++ 库头文件的特定版本来编译源文件(通过 #including 标头),生成的对
象文件必须与相同版本的库链接。 例如,如果使用 Visual Studio 2015 Update 3 <immintrin.h>
编
译源文件,则必须使用 Visual Studio 2015 Update 3 vcruntime 库进行链接。 同样地,如果使用 V
isual Studio 2017 版本 15.5 <iostream>
编译源文件,则必须使用 Visual Studio 2017 版本 15.5
标准 C++ 库 msvcprt 进行链接。 不支持混合与匹配。
对于 C++ 标准库,从 Visual Studio 2010 起,通过在标准标头中使用 #pragma detect_mismatch 显
示禁止混合与匹配。 如果尝试链接不兼容的对象文件,或尝试与错误的标准库链接,链接将失败。
CRT 向来不支持混合与匹配,但通常还是能使用混合与匹配(至少在 Visual Studio 2015 和通用 CRT 之
前,都是如此),这是因为 API 接口一直以来的变化不大。 通用 CRT 中断了后向兼容性,以便我们将来维
护向后兼容性。 也就是说,将来我们不打算引入新的、已进行版本管理的通用 CRT 二进制文件。 现有的通
用 CRT 已更新就绪。
为了提供与使用早期版本的 Microsoft C 运行时标头编译的对象文件(和库)的部分链接兼容性,我们提供
库 legacy_stdio_definitions.lib,用于 Visual Studio 2015 及更高版本。 此库为大部分从通用 CR
T 删除的函数和数据导出提供兼容性符号。 legacy_stdio_definitions.lib 提供的兼容性符号集足以满足
大多数依赖项,包括 Windows SDK 所包含的库中的所有依赖项。 但是,对于某些从通用 CRT 删除的符号,
则无法提供兼容性符号。 这些符号包括一些函数(例如,__iob_func)和数据导出(例如,__imp___iob、
__imp___pctype、__imp___mb_cur_max)。
如果静态库由较旧版本的 C 运行时标头生成,建议按以下顺序采取下列操作:
使用新版本的 Visual Studio 和通用 CRT 标头重新生成静态库,以支持与通用 CRT 的链接。 此方法是完全
受支持的选项,也是最佳选项。
如果无法(或不希望)重新生成静态库,则可以尝试使用 legacy_stdio_definitions.lib 进行链接。 如果
它满足静态库的链接时间依赖关系,则需要彻底测试静态库在二进制文件中的使用情况,以确保对通用 CRT 所
做的行为变更不会对其造成不利影响。
如果 legacy_stdio_definitions.lib 不能满足静态库的依赖关系,或库不适用于通用 CRT(由于上述行为变
更),则建议将静态库封装到与 Microsoft C 运行时的正确版本链接的 DLL。 例如,如果使用 Visual Studi
o 2013 生成静态库,则也需要使用 Visual Studio 2013 和 Visual Studio 2013 C++ 库来生成此 DLL。 通
过将库构建到 DLL 中,可封装实现的详细信息(此详细信息是在特定版本 Microsoft C 运行时上的它的依赖项
)。 需要注意不要让 DLL 接口泄露有关其所使用的 C 运行时的详细信息,例如,通过返回跨 DLL 边界的 FILE*
,或通过返回 malloc 分配的指针并让调用方释放它。
在单个进程中使用多个 CRT 本身不是问题(实际上,大多数进程最终将加载多个 CRT DLL;例如,Windows 操作
系统组件将依赖于 msvcrt.dll,而 CLR 也将依赖于自己的专用 CRT)。 当混杂不同 CRT 中的状态时,会出现
问题。 例如,不应使用 msvcr110.dll!malloc 分配内存,也不应使用 msvcr120.dll!free 取消分配内存,不
应尝试使用 msvcr110!fopen 打开文件,也不应尝试使用 msvcr120!fread 读取文件。 只要不混杂不同 CRT 中
的状态,就能安全地在单个进程中加载多个 CRT。
Comments | NOTHING