C++:不同翻译单元中具有相同名称的不同类

2024-04-21

考虑以下示例:

// usedclass1.hpp  
#include <iostream>  
class UsedClass
{  
public:
  UsedClass() { }  
  void doit() { std::cout << "UsedClass 1 (" << this << ") doit hit" << std::endl; }
};  

// usedclass2.hpp  
#include <iostream>
class UsedClass
{
public:
  UsedClass() { }
  void doit() { std::cout << "UsedClass 2 (" << this << ") doit hit" << std::endl; }
};

// object.hpp
class Object
{
public:
  Object();
};

// object.cpp
#include "object.hpp"
#include "usedclass2.hpp"
Object::Object()
{
  UsedClass b;
  b.doit();
}

// main.cpp
#include "usedclass1.hpp"
#include "object.hpp"
int main()
{
  Object obj;
  UsedClass a;
  a.doit();
}

代码编译后没有任何编译器或链接器错误。但输出对我来说很奇怪:

  • Fedora x86_64 上的 gcc (Red Hat 4.6.1-9) 没有优化 [EG1]:

    使用类 1 (0x7fff0be4a6ff) doit hit
    使用类 1 (0x7fff0be4a72e) doit hit

  • 与 [EG1] 相同,但启用了 -O2 选项 [EG2]:

    使用类 2 (0x7fffcef79fcf) doit hit
    使用 1 类 (0x7fff f79f) 击中

  • Windows XP 32 位上的 msvc2005 (14.00.50727.762),无优化 [EG3]:

    已使用Class 1 (0012FF5B) doit hit
    已使用Class 1 (0012FF67) doit hit

  • 与 [EG3] 相同,但启用了 /O2(或 /Ox)[EG4]:

    已使用Class 1 (0012FF73) doit hit
    已使用Class 1 (0012FF7F) doit hit

我期望出现链接器错误(假设违反 ODR 规则)或 [EG2] 中的输出(代码内联,没有从翻译单元导出任何内容,保留 ODR 规则)。因此我的问题是:

  1. 为什么可以输出 [EG1]、[EG3]、[EG4]?
  2. 为什么不同的编译器甚至同一个编译器会得到不同的结果?这让我认为标准在某种程度上没有指定这种情况下的行为。

感谢您的任何建议、评论和标准解释。

Update
我想了解编译器的行为。更准确地说,为什么违反 ODR 时不会生成错误。一个假设是,由于类中的所有函数二手Class1 and 二手Class2被标记为内联(因此 C++03 3.2 是not违反)链接器不报告错误,但在这种情况下输出 [EG1]、[EG3]、[EG4] 看起来很奇怪。


这是标准第 3.2 节中禁止您所做的事情的规则(C++11 措辞):

一个类类型可以有多个定义(第 9 条),枚举类型(7.2),具有外部链接的内联函数(7.1.2)、类模板(第 14 条)、非静态函数模板(14.5.6)、类模板的静态数据成员(14.5.1.3)、类模板的成员函数(14.5.1.1),或未指定某些模板参数的模板特化(14.7、14.5.5)在程序中,前提是每个定义出现在不同的翻译单元中,并且定义满足以下要求。给定这样一个名为D在多个翻译单元中定义,然后

  • 每个定义D应由相同的令牌序列组成; and

  • 在每个定义中D,根据 3.4 查找的相应名称应指代定义中定义的实体D,或在重载解析(13.3)之后和部分模板特化(14.8.3)匹配之后应引用相同的实体,除了名称可以引用const如果对象在所有定义中具有相同的文字类型,则具有内部链接或无链接的对象D,并且用常量表达式(5.19)初始化该对象,并使用该对象的值(但不是地址),并且该对象在所有定义中具有相同的值D; and

  • 在每个定义中D,对应实体应具有相同的语言链接;和

  • 在每个定义中D、所指的重载运算符、对转换函数、构造函数、运算符 new 函数和运算符删除函数的隐式调用应引用同一函数,或引用 D 定义中定义的函数;和

  • 在每个定义中D,(隐式或显式)函数调用使用的默认参数被视为其标记序列存在于定义中D;也就是说,默认参数须满足上述三个要求(并且,如果默认参数具有带默认参数的子表达式,则此要求递归适用)。

  • if D是一个具有隐式声明构造函数的类(12.1),就好像该构造函数在每个使用 odr 的翻译单元中隐式定义,并且每个翻译单元中的隐式定义应为基类调用相同的构造函数或以下类别的成员D.

在您的程序中,您违反了 ODRclass UsedClass因为不同编译单元的token是不同的。您可以通过移动定义来解决这个问题UsedClass::doit()在类主体之外,但相同的规则适用于内联函数的主体。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++:不同翻译单元中具有相同名称的不同类 的相关文章

  • 具有相同参数类型但具有不同常量限定符的 std::vector 的转换

    问题很简单 静态转换 或其他一些转换 通常是安全的 std vector lt Foo gt to std vector lt const Foo gt 就二进制而言 我不明白为什么本机类型会有所不同 毕竟const是一种语言约束 不应影响
  • Linq - 从表达式 创建表达式

    我有一个谓词Expression
  • Caliburn.Micro - ShowDialog() 如何关闭对话框?

    EDIT 新信息 刚刚设法让记录器工作 老实说 我不知道 cm 有一个 并且在尝试使用时收到此消息TryClose TryClose requires a parent IConductor or a view with a Close m
  • ASP.NET Web 应用程序中的身份验证遇到问题

    我正在尝试对从登录页面登录我的 Web 应用程序的用户进行身份验证 我正在使用本教程 http support microsoft com kb 301240作为指南 它几乎准确地解释了我希望做什么 但是当我输入用户名和密码时 验证不起作用
  • 将公历日期转换为儒略日期,然后再转换回来(随着时间)

    我正在编写一个程序 必须将当前的公历日期和时间转换为儒略日期 然后再转换回公历门 最终我需要添加能够添加年 月 日 小时 分钟和秒的功能 但我需要先解决这部分问题 现在我已经从公历日期转换为儒略日期 所以从逻辑上讲 我觉得我应该能够以某种方
  • 如何从 Qt 应用程序通过 ODBC 连接到 MySQL 数据库?

    我有一个新安装的 MySQL 服务器 它监听 localhost 3306 从 Qt 应用程序连接到它的正确方法是什么 原来我需要将MySQL添加到ODBC数据源 我在遵循这个视频教程后做到了这一点 https youtu be K3GZi
  • 如何在C中同时运行两个子进程?

    所以我开始学习并发编程 但由于某种原因我什至无法掌握基础知识 我有一个名为 fork c 的文件 其中包含一个 main 方法 在此方法中 我将 main 分叉两次 分别进入子进程 1 和 2 在孩子 1 中 我打印了字符 A 50 次 在
  • 控制台应用程序中使用 Unicode 字符的 _tprintf

    我正在从 Unicode 构建的控制台应用程序 使用 C 和 Visual Studio 2008 执行这个简单的输出 此代码旨在在 Windows 上运行 tprintf L Some sample string n 一切正常 但是如果我
  • 如何自定义 Google 测试失败消息?

    我编写了一个如下所示的 Google 测试 它将一些计算值与 CSV 文件中预期存储的值进行比较 class SampleTest public testing Test public void setupFile const std st
  • C# 枚举到字符串自动转换?

    是否可以让编译器自动将我的 Enum 值转换为字符串 这样我就可以避免每次都显式调用 ToString 方法 这是我想做的一个例子 enum Rank A B C Rank myRank Rank A string myString Ran
  • 处理“未找到细胞”。 Excel 中的错误

    我正在使用 Excel VSTO 应用程序并使用以下代码在工作表中查找错误单元格 Excel Range rngTemp Excel Range rngErrorRange Excel Worksheet Sheet1 Excel Work
  • 如何从外语线程调用Python函数(C++)

    我正在开发一个程序 使用 DirectShow 来抓取音频数据 媒体文件 DirectShow 使用线程将音频数据传递给回调 我的程序中的函数 然后我让该回调函数调用另一个函数 Python 中的函数 我使用 Boost Python 来包
  • 当需要不同数量和类型的参数时如何创建操作委托列表

    我们有一组大约两打的类 它们继承自具有抽象 Validate 方法的基类 当然 每个类都有不同的验证需求 但它们之间的不同组合需要规则 因此 正如您可以想象的那样 这导致了大量代码重复 例如 A 类需要规则 1 3 6 和 9B 类需要规则
  • 如何在 C# 中更改公共 IP 地址

    我正在创建一个 C winform 应用程序 我想在其中更改公共 IP 地址 而不是像 Hotspot Shield ZenMate OpenVPN 等那样更改 IPv4 地址 我已经检查了以下链接 但没有找到足够的帮助 所以我发布了这个问
  • 选择合适的IDE

    您会推荐使用以下哪种 IDE 语言来在 Windows 下开发涉及识别手势并与操作系统交互的项目 我将使用 OpenCV 库来执行图像处理任务 之后 我将使用 win32 API 或 NET 框架与操作系统交互 具体取决于您建议的工具 性能
  • 连接到没有元数据的网络服务

    我想连接到此网络服务 https training api temando com schema 2009 06 server wsdl https training api temando com schema 2009 06 serve
  • 从脚本启用/禁用 GameObject 组件 [Unity3D]

    我需要获取一个脚本中设置的布尔值 放入名为 bouclier 的变量 以启用或禁用游戏对象 该变量位于游戏对象 Player 中 此处右下角 我需要启用或禁用这个游戏对象 Bouclier01 为此 我将脚本附加到游戏对象 Bouclier
  • 如何在c#中创建多线程

    我需要监听机器中的所有串行端口 假设我的机器有 4 个串行端口 我必须创建 4 个线程并开始分别使用附加线程监听每个端口 我使用此代码来获取我的机器中的端口数量 private SerialPort comPort new SerialPo
  • 在windows + opengl中选择图形设备

    我知道如何使用 openGL 打开窗口 使用 Win32 或其他工具包 但是当系统有2块显卡时 如何选择要渲染的图形设备 我的编程语言是 C 我专注于 Windows 但任何示例都将受到欢迎 编辑 也许更好地解释我的问题是个好主意 以便添加
  • 将一个 IEnumerable 拆分为多个 IEnumerable

    我是 linq 新手 我需要根据指示器将 Couple string text bool Indicator 类型的 IEnumerable 拆分为多个 IEnumerable 我尝试使用skipWhile 和 TakeWhile 但没有找

随机推荐

  • linux脚本杀死java进程

    我想要linux脚本来杀死在控制台上运行的java程序 以下是作为 jar 运行的进程 rapp s1 dlap0 ps ef grep java rapp 9473 1 0 15 03 pts 1 00 00 15 java jar ws
  • Ruby on Rails:如何将占位符文本添加到 f.text_field?

    我怎样才能添加placeholder发短信给我的f text field字段 以便默认情况下预先编写文本 并且当用户在字段内单击时 文本会消失 允许用户输入新文本 对于 Rails gt 3 0 您可以简单地使用placeholder op
  • .gitignore 和 Visual Studio 项目:忽略 bin/Debug 目录,但不忽略 bin/Release 目录

    我在 git 存储库中有一个 C Visual Studio 项目 我想忽略内容bin Debug目录 但不是目录的内容bin Release 目录 我已经添加bin Debug to my gitignore文件 但它似乎不起作用 它包括
  • 谷歌浏览器缓存

    我有一个嵌入 flash flex 应用程序的 html 页面 我有以下标题 此外 每次发布应用程序的新版本时 我都会更改文件名 因此 它变得类似于 MyApp v1 swf 然后更新为 MyApp v2 swf 尽管如此 chrome仍然
  • 使用当前 HTTP 请求身份作为 SharpSVN 的默认凭据

    我正在尝试通过 Web 应用程序调用 SharpSVN 中的 RemoteCreateDirectories 并希望凭据是已登录用户的凭据 这可以隐式完成还是需要用户名和密码 如下例所示 using var svnClient new Sv
  • MySQL 中可以将一个别名除以另一个别名吗?

    我有一个多表查询 与此类似 简化版 SELECT columns count table2 rev id As rev count sum table2 rev rating As sum rev rating FROM table1 LE
  • D3.js 如何将我的真实数据合并到饼图中

    我是 D3 和数据可视化的新手 在加载真实数据时遇到一些问题 您将在以下部分中找到我的代码 现在我有一些数据存储在数组中 现在我想做的是将数据库中的实际数据存储到饼图中 另外 如果我这样做 var mydata d3 json mydata
  • 如何在Anaconda Python(Windows平台)中安装xgboost?

    我是一个 Python 新用户 我从以下链接下载了最新的 Anaconda 3 2 4 1 Python 3 5 https www continuum io downloads https www continuum io downloa
  • MySQL选择结果保存到C#变量中

    你能检查我的代码并回答我如何将 mysql 选择结果保存到 C 字符串中吗 try MySqlDataReader reader null string selectCmd SELECT FROM TabelaUtilizatori MyS
  • ReactiveCommand 传递命令参数

    我想用命令来实现文本框中的KeyDown事件 我想让命令能够识别哪个键输入 例如 KeyEventArgs 在 KeyDown Event 中执行操作并执行其他一些操作 所以我想将命令参数传递给ReactiveCommand 就像Event
  • Python selenium:DevTools 监听 ws://127.0.0.1

    今天 当我使用 chromedriver 运行 selenium 时 我在控制台上收到此消息 我该如何抑制这种情况 DevTools listening on ws 127 0 0 1 12740 devtools browser 9710
  • 更改 Integration Services 项目中的 .NET Framework

    在 Visual Studio 2013 中创建新的 Integration Services 项目时 我可以选择要定位的 NET 框架 如何查看现有项目所针对的 NET 框架并可能对其进行更改 您需要打开脚本任务之一并单击 编辑脚本 按钮
  • 如何在 R 中按下传单弹出窗口时创建事件?

    当我单击传单多边形时 我想让 tabPanel 变为闪亮 我对如何做到这一点有一些想法 但我找不到实现它们所需的信息 我在选项卡面板中有传单 但我想在单击多边形时切换到另一个选项卡 leaflet llmap gt addTiles gt
  • 使用 cmake 构建项目后如何运行 ctest

    我希望每次成功构建项目时都启动测试 如果某些测试被破坏 我希望我的构建也被破坏 默认情况下 我需要通过运行来手动运行测试ctest命令 CTest 实际上可以构建项目 但我使用调用的 IDEmake建立资源 和make不运行测试 我将此命令
  • php 7 无法初始化 sqlsrv

    我搜索了一整天 寻找 php 7 VC14 x64 Thread Safe 上 sqlsrv dll 的解决方案 但没有找到解决方案 有没有人解决这个问题 04 Oct 2015 19 48 05 UTC PHP Warning PHP S
  • UNNotificationServiceExtension:内存限制?

    我正在尝试实现 UNNotificationServiceExtension 但我的代码似乎经常失败 只需说明 Program ended with exit code 0 我正在尝试在扩展中使用 FMDB Sqlite3 模块 似乎我可能
  • 诊断 SQL Server 2005 中的死锁

    我们在 Stack Overflow SQL Server 2005 数据库中发现了一些有害但罕见的死锁情况 我附加了分析器 使用设置了跟踪配置文件这篇关于解决死锁问题的优秀文章 http www simple talk com sql l
  • 如何仅将缩进序列化应用于某些属性?

    我想以人类可读的方式将 NET 对象序列化为 JSON 但我希望对对象的属性或数组的元素是否最终位于自己的一行上有更多的控制 目前我正在使用 JSON NETJsonConvert SerializeObject object Format
  • 如何改变字典中的数组?

    我在操场上尝试过以下操作 var d1 String String d1 a String var a1 d1 a a1 append s1 println d1 输出是 a 我希望 a s1 改变字典中数组的正确方法是什么 在 swift
  • C++:不同翻译单元中具有相同名称的不同类

    考虑以下示例 usedclass1 hpp include