拆分长方法维护类接口

时间:2011-12-07 10:31:49

标签: c++ interface methods inline

在我的图书馆里有一个这样的课程:

class Foo {
public:
    void doSomething();
};

现在,doSomething()的实施已经增长了很多,我想用两种方法将其拆分:

class Foo {
public:
    void doSomething();
private:
    void doSomething1();
    void doSomething2();
};

doSomething()实施的目的是:

void Foo::doSomething() {
    this->doSomething1();
    this->doSomething2();
}

但是现在类接口已经改变了。如果我编译这个库,那么使用这个库的所有现有应用程序都不会工作,外部链接就会改变。

如何避免破坏二进制兼容性?

我想内联解决了这个问题。这样对吗?它是便携式的吗?如果编译器优化无法使用这些方法,会发生什么?

class Foo {
public:
    void doSomething();
private:
    inline void doSomething1();
    inline void doSomething2();
};

void Foo::doSomething1() {
    /* some code here */
}

void Foo::doSomething2() {
    /* some code here */
}

void Foo::doSomething() {
    this->doSomething1();
    this->doSomething2();
}

修改 我在方法拆分之前和之后测试了这段代码,它似乎保持了二进制兼容性。但我不确定这会在每个操作系统和每个编译器以及更复杂的类(使用虚方法,继承......)中起作用。有时候在添加像这样的私有方法后我的二进制兼容性中断,但现在我不记得在哪种特定情况下。也许是因为符号表格被索引查看(比如 Steve Jessop 在他的回答中注释)。

3 个答案:

答案 0 :(得分:2)

严格地说,根本改变类定义(以你显示的任何一种方式)是违反单一定义规则并导致未定义的行为。

实际上,向类中添加非虚拟成员函数可以在每个实现中保持二进制兼容性,因为如果没有,那么您将失去动态库的大部分好处。但是C ++标准对动态库或二进制兼容性并没有太多(任何东西?),所以它不能保证你可以做出哪些改变。

因此在实践中,只要动态链接器按名称查找符号表中的条目,更改符号表就无关紧要了。符号表中的条目比以前多,但这没关系,因为所有旧条目仍然具有相同的错位名称。对于您的实现,私有和/或内联函数(或您指定的任何函数)可能不是dll导出的,但您不需要依赖它。

我使用了一个系统(Symbian),其中符号表中的条目没有按名称查找,它们是通过索引查找的。在该系统上,当您向动态库添加任何内容时,必须确保将任何新函数添加到符号表的末尾,这是通过在特殊配置文件中列出所需顺序来完成的。您可以确保二进制兼容性没有被破坏,但它相当繁琐。

因此,您可以检查您的C ++ ABI或编译器/链接器文档是绝对确定的,或者只是接受我的话,然后继续。

答案 1 :(得分:0)

这里没有问题。 Foo::doSomething()的名称重整始终是相同的,无论其实现如何。

答案 2 :(得分:0)

我认为如果添加非虚方法,类的ABI将不会改变,因为非虚方法不存储在类对象中,而是存储为具有错位名称的函数。只要不添加类成员,就可以添加任意数量的函数。

相关问题