2010-08-05 80 views
2

我们在共享库的版本1的结构体,我们需要保持的ABI:维护ABI:添加构造函数结构

struct Person 
{ 
    std::string first_name; 
    std::string last_name; 
} 

在第2次修订,我们正在改变人到这一点:

class Person 
{ 
public: 
    Person(const std::string &f, const std::string &l); 

    std::string first_name; 
    std::string last_name; 
} 

为了保持源代码兼容性,我们想改变人的逆转1,使代码编译反对新的头文件将运行和代码重新编译不能运行。

我们可以用两个新的非内联的构造函数如下:

class Person 
{ 
public: 
    Person(); 
    Person(const std::string &f, const std::string &l); 

    std::string first_name; 
    std::string last_name; 
} 

我们正在做的这一切都与G ++。在使用nm查看生成的共享库时,我没有看到普通结构的构造函数或析构函数,所以我猜测那些没有重新编译的代码只会像前面那样在调用站点构造Person。任何重新编译的代码都将使用无参数构造函数。

我看到的唯一问题是,如果我们需要回滚到没有构造函数的共享库的较旧版本,那么编译的任何代码都会中断,但我并不担心这种情况。

回答

2

我认为它应该工作,假设你明确的默认ctor和以前使用的隐式ctor做的是一样的事情。在这个简单的例子。然而,恕我直言很难预测或知道编译器会做/改变什么。我不会相信它,我宁愿重新编译图书馆用户,如果我是你的话。

2

它可能“有效”,但是您将打破“一个定义规则”,并且就C++标准而言,您将在Undefined Behavior land中关闭,这不是一个好地方。

+0

更多关于“不是好地方” – 2010-08-05 22:38:07

3

以下情况如何?

class NewPerson : public Person 
{ 
public: 
    NewPerson(const std::string &f, const std::string &l) 
    { 
     first_name = f; 
     last_name = l; 
    } 
} 
+0

这是一个非常好的主意(与其他人相比)。 :-) – 2010-08-05 22:36:53

+0

除非他有某个人的数组或矢量,或者正在使用Person值,我可能会偷偷摸摸地怀疑。 – 2010-08-05 23:11:01

+0

是的,我们实际上有一个“Person”的向量,它们只是一堆用于数据库查询的参数,这就是为什么我们不关心结构设计的原因。 – 2010-08-06 00:36:40

1

在不破坏二进制兼容性的情况下向类或结构中添加新的非虚函数应该没问题。这是因为类函数是以一个隐含的this作为其第一个参数的普通函数实现的。

但是,如果添加新的虚拟函数,则可能会破坏兼容性,因为新函数将强制修改vtable,从而可能破坏兼容性。

因此,添加额外的构造函数(永远不会是虚拟的)不会破坏兼容性。如果你要添加一个虚拟析构函数,你很可能会破坏兼容性。

+0

说的是谁?实施细节和ABI因此完全落实到实施中。如果你打算说它没有打破它们,你最好说出你正在谈论的编译器版本和操作系统。由于旧代码使用编译器生成的默认构造函数,而新代码具有用户定义的构造函数。谁说这些具有相同的ABI。 – 2010-08-05 22:41:05

+0

@Martin,标准对ABI的问题没有提及,所以在技术上你是正确的。但是我挑战你找到一个以任何其他方式实现非虚函数的C++ ABI。 – doron 2010-08-05 22:56:23

+0

@马丁,这是否甚至重要?只要类的二进制布局相同,那么Person是如何构造的,无论是在调用代码中还是通过构造函数内联? – 2010-08-06 00:35:08