编译期封装

  • Pimpl(Pointer to Implementation)意思为具体实现的指针,它通过一个私有的成员指针,将指针所指向的类的内部实现和数据进行隐藏。

实现

在看Qt源码时,Qt的源码中有大量的使用Pimpl,其中源码中的d 指针和q 指针都是用Pimpl来实现的。其中具体实现的原理可以参考D指针的实现,参考Qt中的实现,我们来封装自己的。

global.h

#pragma once

template<typename T> static inline T*qGetPtrHelper(T* ptr){return ptr;}
template<typename Wrapper> static inline typename Wrapper::pointer qGetPtrHelper(const Wrapper& p){
    return p.get();
}
//reinterpret_cast < new_type > ( expression )
// 前置隐藏实现类  
#define C_CLASS_PRIVATE(Class) \     
    inline Class##Private* d_func() noexcept\
    {return reinterpret_cast<Class##Private*>(qGetPtrHelper(d_ptr));} \
    inline const Class##Private* d_func() const noexcept \
    {return reinterpret_cast<const Class##Private* >(qGetPtrHelper(d_ptr));}\
    friend class Class##Private;

// noexcept  告诉编译器这段代码不会出现异常 不需要特殊优化处理
// 对外接口类
#define C_CLASS_PUBLIC(Class) \    
    inline Class* q_func() noexcept {return static_cast<Class*>(q_ptr);} \
    inline const Class* q_func() const noexcept {return static_cast<const Class* >(q_ptr);}\
    friend class Class;

#define C_P(Class) Class##Private* const d = d_func()
#define C_Q(Class) Class* const q = q_func()

product.h

#pragma once

#include "global.h"
#include <memory>
#include <string>


using namespace std;

class ProductPrivate;

class Product
{
    C_CLASS_PRIVATE(Product);

public:
    explicit Product(int num = 1);
    ~Product();
    string getName() const;
    void setName(const string &name);
    float getPrice() const;
    void setPrice(float price);
    //int getNum(){ return num;};

protected:
    //int num = 5;

protected:
    // 定义实现类指针
    std::unique_ptr<ProductPrivate> d_ptr;
};

product.cpp

#include "product.h"

#include <iostream>
#include <memory>
using namespace std;

class ProductPrivate
{
    C_CLASS_PUBLIC(Product)
public:
    ProductPrivate(){

    }

    ~ProductPrivate(){

    }
    string getName() const { 
        return name;
    }

    bool setName(const string& names){
        this->name = names;
    }

    void printNum(){
        C_Q(Product);
        //std::cout<<""<<q->num;
    }
    string name;
    Product* q_ptr;
};

Product::Product(int num)
{
    d_ptr = make_unique<ProductPrivate>();
    // 这里为了让对方可以使用自己的变量,将对方类中的q_ptr来指向自己
    d_ptr->q_ptr = this; 
}

string Product::getName() const
{
    C_P(const Product);
    return d->getName();
}

void Product::setName(const string &name)
{
    C_P(Product);
    d->printNum();
    d->setName(name);
}

float Product::getPrice() const
{
    // Q_D(const Product);
    // return d->price;
}

void Product::setPrice(float price)
{
    // Q_D(Product);
    // d->price = price;
}

其中,参考Qt中的实现,实现了C_PC_Q ,下面是测试文件

#include <iostream>
#include <stdio.h>
#include "product.h"

int main()
{
    Product * p = new Product();
    p->setName("hello ");

    std::cout<<" "<<p->getName()<<std::endl;
}

以后在使用的时候,我们可以直接将global.h文件引入到我们自己的工程里面,然后使用Pimpl

发表评论

电子邮件地址不会被公开。