在我从同事那里继承的项目中,我有带有头和实现的基本c ++类。为了便于理解,我将提供示例情况,因为代码本身太大: bthidtransport.h :
class BtHidTransport
{
public:
BtHidTransport(); // constructor
protected:
virtual ~BtHidTransport(); // destructor
} // BtHidTransport
bthidtransport.cpp :
BtHidTransport::BtHidTransport
{
} // constructor
BtHidTransport::~BtHidTransport()
{
} // destructor
这是基类,现在我们派生了类标题:
bthidtransportfixes.h :
#include "bthidtransport.h"
class BtHidTransportFixes : public BtHidTransport
{
BtHidTransportFixes(); // constructor
virtual ~BtHidTransportFixes(); // destructor
} // BtHidTransportFixes
但是,在特定项目中, BtHidTransportFixes 没有实现文件( .cpp )。项目本身的构建没有错误。如果我在运行时从类中实例化新对象:
BtHidTransport* createdObject=new BtHidTransportFixes();
和 BtHidTransportFixes 没有实现文件( .cpp ),对于父类而言,执行顺序是什么?我正在将 Eclipse 4.3.2 for Windows (主机操作系统为 Windows 7 64bit Ultimate )与 ARM DS-5 5.20.2 编译器一起使用。在项目的任何地方都没有实现BtHidTransportFixes
,我已经在所有项目文件中进行了搜索。使用-O0标志明确地关闭编译器优化。这是构建过程的汇编程序清单:
;;;107 // Create the BT transport first
;;;108 BtHidTransport *btTransport = new BtHidTransportFixes();
00002a 2088 MOVS r0,#0x88
00002c f7fffffe BL _ZN16StartupAllocatednwEj ; StartupAllocated::operator new(unsigned)
000030 4934 LDR r1,|L1.260|
000032 2200 MOVS r2,#0
000034 9100 STR r1,[sp,#0]
000036 4b34 LDR r3,|L1.264|
000038 4611 MOV r1,r2
00003a f7fffffe BL _ZN19BtHidTransportFixesC1EP9BtHidConnP13BtPairingListPK14tBTM_APPL_INFOPK23tBTM_LINK_EVT_CALLBACKS ; BtHidTransportFixes::BtHidTransportFixes()
00003e 4604 MOV r4,r0
和链接器输出:
Stack Usage for BtHidTransportFixes::BtHidTransportFixes() 0x0 bytes.
Stack Usage for BtHidTransportFixes::BtHidTransportFixes() 0x0 bytes.
Stack Usage for BtHidTransportFixes::BtHidTransportFixes__sub_object() unknown bytes.
BtHidTransportFixes::BtHidTransportFixes() 0x0020587d Thumb Code 0 20730_ram_ext.symdefs ABSOLUTE
BtHidTransportFixes::BtHidTransportFixes__sub_object() 0x0020587d Thumb Code 0 20730_ram_ext.symd
构造函数的大小似乎为0,在这里执行什么技巧?为了简化起见,我特意删除了构造函数的参数(在此处,在问题的StackOverflow中),这是我的不好吗?
答案 0 :(得分:6)
它不必构建失败。即使在一个定义规则下隐式使用了虚拟成员函数。
[basic.def.odr] (强调我的意思)
4每个程序应仅包含每个程序的一个定义 该程序中使用的非内联函数或变量 在被遗弃的声明之外; 无需诊断。的 定义可以显式出现在程序中,可以在 标准库或用户定义的库,或者(如果适用) 隐式定义(请参见[class.ctor],[class.dtor]和[class.copy])。 内联函数或变量应在每次翻译中定义 在废弃的语句外使用的单位。
您的工具链不必对其进行警告或构建失败。它可以假装一切都很好。在这种情况下,该程序格式不正确。如果工具链设法解决问题,或者直到运行时崩溃发生时才诊断出问题,那么一切就在合同之内。
答案 1 :(得分:2)
如果程序缺少声明的成员函数的实现,则根本无法执行-链接器将无法生成可执行文件。
缺少实现无关紧要的唯一事情就是是否从未使用相应的类。在这种情况下,链接程序将永远不会被迫寻找实现。
但是,如果您的程序包含-如您所说-下一行
DerivedClass* derivedClass=new DerivedClass();
程序格式错误(链接器应该抱怨)。
答案 2 :(得分:0)
我找到了解决特定问题的方法。指示生成过程文件( .inc )用修补的 bthidtransportfixes.h 替换头文件 bthidtransportfixes.h ,该文件未包含在项目树中本身,但是驻留在 Windows用户主目录中,然后将缺少的代码本身从修补的标头复制到原始内容。如果我清理项目,则操作相反。真是胡说八道,这个项目被搞砸了!这是缺少的构造函数代码,摘自补丁:
BtHidTransportFixes::BtHidTransportFixes(BtHidConn *btHidConn,
BtPairingList *hostList,
const tBTM_APPL_INFO *btmSecCallbacks,
const tBTM_LINK_EVT_CALLBACKS *btmLinkEvtCb) :
BtHidTransport(btHidConn, hostList, btmSecCallbacks, btmLinkEvtCb)
{
#ifdef PROXIMITY_ASSOCIATION_SUPPORT
// Initialize the observer to NULL
proxAssocObserver.pObj = NULL;
#endif
#ifdef FIX_NEED_DISCOVERYLED_TICK
discoveryTickEnabled = hidAppConfig.discoveryLedEnabled;
discoveryTickBasePeriodInMs = 50;
#endif
#ifdef FIX_CQ_911035
ucdConnectRequested = FALSE;
#endif
}
我自己创建了实现文件,将其添加到项目中,将修补的代码放入其中,删除 .inc 命令以包含补丁,添加了新的实现文件以构建过程,现在它像魅力。