没有实现文件 (.cpp) 的派生 class

derived class with no implementation file (.cpp)

在我从同事那里继承的项目中,我有基础 c++ class 和 header 和实现。为了便于理解,我将提供示例情况,因为代码本身太大: bthidtransport.h:

class BtHidTransport
{
public:
    BtHidTransport();    // constructor

protected:
    virtual ~BtHidTransport();   // destructor
}    // BtHidTransport

bthidtransport.cpp:

BtHidTransport::BtHidTransport
{
}   // constructor

BtHidTransport::~BtHidTransport()
{
}   // destructor

这是基础class,现在我们得到class header:
bthidtransportfixes.h:

#include "bthidtransport.h"

class BtHidTransportFixes : public BtHidTransport
{
    BtHidTransportFixes(); // constructor
    virtual ~BtHidTransportFixes();    // destructor
}   // BtHidTransportFixes

但是,在特定项目中,BtHidTransportFixes 没有实现 (.cpp) 文件。项目本身构建没有错误。如果我在运行时从 class 实例化新的 object 并使用:

BtHidTransport* createdObject=new BtHidTransportFixes();

BtHidTransportFixes没有实现(.cpp)文件,parent的执行顺序是什么class?我正在为 Windows 使用 Eclipse 4.3.2(主机 OS 是 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

constructor的大小好像是0,这里到底执行了什么?为了简化,我特意删除了构造函数的参数(此处,在 Whosebug 问题描述中),这是我的错吗?

如果程序缺少已声明成员函数的实现,则根本不会执行 - 链接器将无法构建可执行文件。

唯一没有实现的缺失无关紧要的是,如果从未使用过相应的 class。在这种情况下,链接器永远不会被迫寻找实现。

但是如果你的程序包含——正如你所说的——下面一行

DerivedClass* derivedClass=new DerivedClass();

程序格式错误(链接器应该抱怨)。

它不必构建失败。即使在一个定义规则下隐式使用虚拟成员函数。

[basic.def.odr] (emphasis mine)

4 Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see [class.ctor], [class.dtor] and [class.copy]). An inline function or variable shall be defined in every translation unit in which it is odr-used outside of a discarded statement.

您的工具链不必对此发出警告或无法构建。它可以假装一切都很好。在那种情况下,程序显然是病式的。如果工具链设法绕过问题,或者直到发生运行时崩溃才对其进行诊断,这一切都在合同范围内。

我找到了特定问题的解决方案。指示生成过程文件 (.inc) 将 header 文件 bthidtransportfixes.h 替换为已修补的 bthidtransportfixes.h,它不包含在项目树本身中,但驻留在 Windows 用户主目录 中,然后从修补程序中复制丢失的代码本身header 为原创。如果我清理项目,则操作相反。胡说八道,这个项目一团糟!这里缺少构造函数代码,取自补丁:

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 命令以包含补丁,将新的实现文件添加到构建过程和它现在就像一个魅力。