我仍然认为你试图解决一个问题,该问题更多地与 API/代码、文档的设计中可能存在的缺陷有关,或者与使用它的人缺乏 C++ 知识有关,而“解决方案”是缺点多于优点。
如果 C++ 程序员不知道什么是所有权或不尊重它,并盲目地删除对象或释放指针的内存,那么将会有更大的问题。您可能会将问题转移到代码的不同部分。
话虽如此,现在您可以做的最接近不暴露指针的事情是这样的:
(代码只是概念证明,所以像call
可能需要改进)
#include <iostream>
#include <string>
struct Test {
void foo(int x, int y, std::string str) {
std::cout << x << " " << y << " " << str << std::endl;
}
double test = 0.5;
};
template <typename T>
struct Ptr {
template <auto M, typename... Args>
auto call(Args... args) {
return (obj.*M)(std::forward<Args>(args)...);
}
template <auto M>
auto get() {
return (obj.*M);
}
protected:
T obj;
};
int main() {
Ptr<Test> p;
p.call<&Test::foo>(1, 2, "hello");
std::cout << p.get<&Test::test>() << std::endl;
return 0;
}
但我仍然不认为这是一个好的方法。
用户仍然可以乱搞代码并做一些不好的事情,例如:
int main() {
Ptr<Test> p;
delete &p;
return 0;
}
或者这肯定是未定义的行为,但这并不重要,因为删除不拥有的对象也会在某些时候导致未定义的行为:
template<typename T>
struct Ptr {
protected:
T *obj;
}
template<typename T>
struct Ptr2 {
public:
T *obj;
};
int main()
{
Ptr<Test> p;
Ptr2<Test> *p2 = reinterpret_cast<Ptr2<Test>*>(&p);
std::cout << p2->obj << std::endl;
}
所以没有针对此类事情的保护措施。
除了显示的代码之外,还有一个建议反射 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0578r1.html该功能现在已完成,可以获取有关类型成员的信息,但这并未添加到 c++20 中,并且有一个用于元类 http://www.open-std.org/Jtc1/sc22/WG21/docs/papers/2018/p0707r3.pdf这也尚未包含在标准中。
有了这两个建议,您也许能够实现一些更好用的东西。但我对其好处的担忧仍然存在。