C++ pimpl机制详细讲解
什么是pimpl机制
pimpl,即Private Implementation(私有实现),也叫Opaque Pointer(不透明指针),是一种C++编程技巧/设计模式,它的本质是把类的实现(类的成员变量和方法)隐藏到源文件中,只把类的接口(类的公有成员函数)暴露出去。
pimpl机制的优缺点
优点:
-
隐藏了类的实现细节,可以防止其他程序员干预我们的内部实现。
-
由于所有实现在cpp文件中,可以避免一些头文件常见的循环依赖的问题。
缺点:
-
在每个类中都需要写一个指向实现类的指针,会增加代码量和复杂度。
-
在使用pimpl的类中始终存在指针解引用所带来的额外开销。
pimpl机制的使用方法
1.在头文件中定义一个只有前向声明的类。
//test.h
class Test
{
public:
Test();
~Test();
void test();
private:
class Impl;
Impl* pImpl;
};
2.ccp文件中定义类的实现。
//test.cpp
class Test::Impl
{
public:
void doTest();
~Impl(){ std::cout << "~Impl" << std::endl; }
};
Test::Test()
:pImpl(new Impl)
{
std::cout << "Test" << std::endl;
}
Test::~Test()
{
delete pImpl;
std::cout << "~Test" << std::endl;
}
void Test::test()
{
pImpl->doTest();
}
void Test::Impl::doTest()
{
std::cout << "doTest" << std::endl;
}
3.在使用类的地方,只需要包含头文件即可。
//main.cpp
#include <iostream>
#include "test.h"
int main()
{
Test test;
test.test();
return 0;
}
pimpl机制的示例
示例1:使用pimpl机制实现简单的字符串类
具体实现如下:
#include <string>
class String
{
public:
String();
String(const char* str);
String& operator=(const String& other);
String(const String& str);
~String();
void print() const;
private:
class StringImpl;
StringImpl* pImpl;
};
class String::StringImpl
{
public:
StringImpl();
StringImpl(const char* str);
~StringImpl();
std::string str;
};
String::String()
:pImpl(new StringImpl)
{}
String::String(const char* str)
: pImpl(new StringImpl(str))
{}
String::String(const String& str)
:pImpl(new StringImpl(str.pImpl->str))
{}
String& String::operator=(const String& other)
{
if (pImpl == other.pImpl)
return *this;
StringImpl* tmp = pImpl;
pImpl = new StringImpl(other.pImpl->str);
delete tmp;
return *this;
}
String::~String()
{
delete pImpl;
}
void String::print() const
{
std::cout << pImpl->str << std::endl;
}
String::StringImpl::StringImpl()
{}
String::StringImpl::StringImpl(const char* str)
:str(str)
{}
String::StringImpl::~StringImpl()
{}
int main()
{
String str1("hello");
String str2 = str1;
str1.print();
str2.print();
String str3;
str3 = str2;
str3.print();
return 0;
}
以上示例代码中,String类的数据成员都放在了StringImpl类中。
示例2:使用pimpl机制实现图形类
具体实现如下:
class Shape
{
public:
virtual void draw() = 0;
virtual ~Shape() {}
};
class Rectangle : public Shape
{
public:
void draw() { std::cout << "draw rectangle" << std::endl; }
};
class Circle : public Shape
{
public:
void draw() { std::cout << "draw circle" << std::endl; }
};
class ShapeFacade
{
public:
ShapeFacade(Shape* shape);
void draw();
~ShapeFacade();
private:
Shape* pShape;
};
class ShapeFacade::Impl
{
public:
ShapeFacade::Impl(Shape* shape)
: pShape(shape)
{}
void draw()
{
pShape->draw();
}
private:
Shape* pShape;
};
ShapeFacade::ShapeFacade(Shape* shape)
:pImpl(new ShapeFacade::Impl(shape))
{}
ShapeFacade::~ShapeFacade()
{
delete pImpl;
}
void ShapeFacade::draw()
{
pImpl->draw();
}
int main()
{
ShapeFacade rect(new Rectangle);
rect.draw();
ShapeFacade circle(new Circle);
circle.draw();
return 0;
}
以上示例代码中,Shape类是一个纯虚基类,用于定义图形类的接口。Rectangle和Circle类是Shape的具体实现。ShapeFacade类是一个门面类,用于给外部程序呈现简洁的接口,它的实现被隐藏在Impl类中。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++ pimpl机制详细讲解 - Python技术站