【发布时间】: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