C++在使用PImpl技术时,template/typename的不常见用法
Posted 烧饼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++在使用PImpl技术时,template/typename的不常见用法相关的知识,希望对你有一定的参考价值。
PImpl:Pointer to implementation,常用于隐藏实现细节,构造拥有稳定 ABI 的 C++ 库接口,及减少编译时依赖。
在使用pimpl技术时,pimpl是类静态变量,对其在源文件中的实现需要使用typename关键字
对于模板类的静态成员变量的定义,你需要使用完整的模板类型限定符来指定 std::unique_ptr
的类型。在这个示例中,我们使用 typename MyClass<T>::Impl
来指定 std::unique_ptr
的类型。
// MyClass.h
#include <memory>
template<typename T>
class MyClass
public:
void doSomething();
private:
class Impl;
static std::unique_ptr<Impl> p_impl; // 静态 p_impl 变量的声明
;
// MyClass.cpp
template<typename T>
class MyClass<T>::Impl
public:
void doSomething()
// 实现具体逻辑
std::cout << "Doing something..." << std::endl;
;
template<typename T>
std::unique_ptr<typename MyClass<T>::Impl> MyClass<T>::p_impl = std::make_unique<typename MyClass<T>::Impl>(); // 静态 p_impl 变量的定义
template<typename T>
void MyClass<T>::doSomething()
p_impl->doSomething();
如果一个模板类使用p_impl技术,同时内部包含模板函数,那么模板函数的调用需要额外使用template关键字
在最后的代码p_impl->template doSomething<U>();
处,使用template关键字告诉编译器我们正在引用一个模板成员函数doSomething<U>()
。不使用template关键字会报错
// MyClass.h
#include <memory>
template<typename T>
class MyClass
public:
MyClass();
template<typename U>
void doSomething();
private:
class Impl;
std::unique_ptr<Impl> p_impl;
;
// MyClass.cpp
template<typename T>
class MyClass<T>::Impl
public:
template<typename U>
void doSomething()
// 实现具体逻辑
std::cout << "Doing something with type " << typeid(U).name() << "..." << std::endl;
;
template<typename T>
MyClass<T>::MyClass() : p_impl(std::make_unique<Impl>())
template<typename T>
template<typename U>
void MyClass<T>::doSomething()
p_impl->template doSomething<U>();
何时在 C++ 中的嵌套类上使用 Pimpl 模式,反之亦然?
【中文标题】何时在 C++ 中的嵌套类上使用 Pimpl 模式,反之亦然?【英文标题】:When to use Pimpl pattern over Nested class in C++ or vice versa? 【发布时间】:2019-08-01 10:05:23 【问题描述】:在 C++ 中,大多数开发人员都使用 pimpl idiom 或 opaque pointers 对公共 API 隐藏私有数据/实现,例如:
-
=> 第一种情况 ## 不透明指针和 PIMPL 成语 ##
//在头文件中
class Node;
class Graph
public:
A();
private:
Node* m_nodeImpl;
// 类节点将在各自的cpp中定义
2。 =>第二种情况##内部类/嵌套类方法##
//在头文件中
class Graph
public:
Graph();
private:
class Node
// implementation goes here
Node* m_nodeImpl;
问题是...
-
从类设计的角度来看,这两者之间的实际区别是什么(可能是设计模式)?
每种方法的优缺点是什么?
【问题讨论】:
您可以将两者结合起来,您只需声明Graph::Node
类,并在源文件中定义。
至于区别,在第二个示例中,人类阅读头文件可以看到Node
类的详细信息。
@Someprogrammerdude 我认为这是 pimpl/opaque_ptr 相对于嵌套类 impl 的主要优势,对吧? (甚至隐藏细节)
通常这不是“隐藏”人类的问题,而是依赖问题。 IE。如果Node
的实现(和声明)取决于其他一些类,则需要将其包含在标题中。在 PIML 情况下,您不需要这个。这对于例如不需要公开实现细节的 API 类来说可能很重要。
@sklott 是的,我忘记了这一点,感谢您再次引起我的注意,是的,因此考虑到这两个因素,pimpl 是首选,对吧?那么实际上何时在 C++ 中使用内部类?除了人类可读的东西
【参考方案1】:
你混淆了几件事:
第一个例子
Type: opaque - 这意味着类型 name 对该标头的用户可见,但定义是隐藏的。
当您想与用户共享指针时,不透明类型特别有用,而不是它指向 的详细信息(或者阻止用户摆弄它,或者打破依赖关系)。
存储:粉刺。这只是意味着用户知道您(可能)在某处有一个 opaque 类型的实例,并且他们知道您的***对象的大小包括该指针。
第二个例子
类型:嵌套 - 这样可以避免污染封闭的命名空间(因此在您的程序的同一命名空间中可以有其他类型的 Node
,与第一个示例不同)但会暴露所有细节。
请注意,您的嵌套类型也可以前向声明,以控制可见性和命名空间污染。
存储:丢失。你是不是也想在这里有一个Node *m_impl
?否则,这些示例无法直接进行比较,因为您的 Graph
无处可保留 Node
,但是声明了类型。
【讨论】:
感谢您的简短而清晰的描述,Totally forgot to add Node impl ptr on 2nd example
,我明白了您的意思。以上是关于C++在使用PImpl技术时,template/typename的不常见用法的主要内容,如果未能解决你的问题,请参考以下文章