【问题标题】:Are classes allowed to have different definitions across different translation units in a program?是否允许类在程序中的不同翻译单元中具有不同的定义?
【发布时间】:2020-01-09 05:41:11
【问题描述】:

如果类在每个翻译单元中最多定义一次,那么在不同的翻译单元中以不同的方式定义一个类是否格式正确?

用例是在没有动态分配的情况下访问实现细节。 C++ 代码将对 C 库已分配的指针进行操作。

为了举例,请忽略内存泄漏。

common.hpp

#pragma once

namespace Test {

class Impl;

class A {
    void *ptr;
    A(void *ptr) : ptr(ptr) {}
    friend class Impl;

   public:
    int plus_one();
};

class B {
    void *ptr;
    B(void *ptr) : ptr(ptr) {}
    friend class Impl;

   public:
    int plus_two();
};

class Factory {
   public:
    A getA(int val);
    B getB(int val);
};

}  // namespace Test

A.cpp

#include "common.hpp"

namespace Test {

class Impl {
   public:
    static int as_int(A *a) { return *static_cast<int *>(a->ptr) + 1; }
};

int A::plus_one() { return Impl{}.as_int(this); }

}  // namespace Test

B.cpp

#include "common.hpp"

namespace Test {

class Impl {
   public:
    static int as_int(B *b) { return *static_cast<int *>(b->ptr) + 2; }
};

int B::plus_two() { return Impl{}.as_int(this); }

}  // namespace Test

Factory.cpp

#include "common.hpp"

namespace Test {

class Impl {
   public:
    static A getA(int val) { return A(new int{val}); }
    static B getB(int val) { return B(new int{val}); }
};

A Factory::getA(int val) { return Impl{}.getA(val); }
B Factory::getB(int val) { return Impl{}.getB(val); }

}  // namespace Test

main.cpp

#include <iostream>

#include "common.hpp"

int main() {
    Test::Factory factory;
    std::cout << factory.getA(1).plus_one() << std::endl;
    std::cout << factory.getB(1).plus_two() << std::endl;
    return 0;
}

输出:

$ g++ A.cpp B.cpp Factory.cpp main.cpp -o test 
$ ./test
2
3

【问题讨论】:

  • 这些不同的Impl 似乎无关——为什么不直接声明几个朋友类型呢?
  • @DavisHerring 已经有一段时间了。我不完全记得用例的细节,但后来我通过向上游提交一个补丁来解决它,用extern "C" 保护他们的 C 标头,所以我不必经历这些丑陋的黑客或在移植的库中重复地重新声明所有内容. (但坦率地说,好奇更能激发这个问题。)

标签: c++ linkage one-definition-rule


【解决方案1】:

不,同一个类类型不允许有不同的定义。您的程序直接违反了 ODR,并且表现出未定义的行为。

[basic.def.odr]

6 一个类类型可以有多个定义,[...] 在 一个程序,前提是每个定义都以不同的形式出现 翻译单元,并提供定义满足以下条件 要求。给定这样一个名为 D 的实体,在不止一个 翻译单元,然后

  • D 的每个定义都应由相同的标记序列组成;和
  • [...]

[...] 如果 D 的定义满足所有这些要求,那么 行为就好像 D 有一个单一的定义。如果 D 的定义不满足这些要求,则行为 未定义。

您的两个定义在它们的标记序列上已经很明显不同了,因此不支持 ODR 的条件。

【讨论】:

    猜你喜欢
    • 2016-03-29
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 2018-06-15
    • 1970-01-01
    • 2019-02-02
    • 1970-01-01
    • 2016-10-27
    相关资源
    最近更新 更多