名称/名称空间相同但成员不同的结构

时间:2018-11-05 21:26:41

标签: c++ c++11 struct

我看到我在这篇帖子vector of structs inline initialization. braced-init-list

中描述了一些奇怪的行为

我希望消除这种不确定行为的一种可能来源。我有以下两个类AB都向前声明struct Foo,但是cpp文件定义了如下的实际结构。

// This is A.h
namespace app {
    struct Foo;
    class A {
    private:
        std::vector<Foo> fooList;
    };
}

// This is A.cpp
struct app::Foo {
    std::string first;
    std::string second;
    unsigned flag;
};


// This is B.h
namespace app {
    struct Foo;
    class B {
    private:
        std::vector<Foo> fooList;
    };
}

// This is B.cpp
struct app::Foo {
    std::string first;
    std::string second;
    bool flag;
    float value;
};

请注意,结构Foo在cpp文件A.cppB.cpp中具有不同的成员。类AB从不公开成员fooList。由于前向声明完全相同,因此是否有可能在结构A.h的文件B.hFoo中,所生成的代码可以使用其中之一。这可以解释我在链接问题中看到的问题。

换句话说,当对在Foo中调用的结构B.cpp使用braced-init-list时,可以保证将使用Foo中定义的B.cpp或同样可能也使用Foo中定义的A.cpp吗?

即使在写这篇文章时,我也立即意识到这种实现是一种不好的做法,因为Foo本身是类AB的内部,并且实际上应该在类本身的私有部分。

1 个答案:

答案 0 :(得分:9)

这违反了ODR(一种定义规则)。

程序格式错误,无需诊断。

如果这样做,C ++标准绝对允许任何行为。它可以“工作”,可以选择其中一个然后丢弃另一个,可以工作直到重新链接,然后可以格式化硬盘。

我已经在一个真实的项目中做到了这一点;我们有一个矩阵标头,您可以在其中包含令牌(如果它支持float或double的话)之前定义令牌。

这是“有效的”,而我们从未在同一个DLL中使用两个版本。然后我们使用了两个版本。

编译器将基于一组巧合为结构选择一种或另一种大小,并根据一组稍有不同的巧合选择一种构造函数或另一种构造函数。我们有大量的内存损坏问题。但仅在某些版本上有时如此。

我们通过将代码包装在一个名称空间中来对其代码进行“修复”,该名称空间中包含标量类型,然后using将其引入外部名称空间。