C++降低编译依赖—Pimpl和虚基类

C++降低编译依赖—Pimpl和虚基类

方法一:声明和实现分离

这当然是最容易实现的方式,把代码分为.cpp.h文件

方法二:Pimpl(Pointer to Implementation)

通过一个私有的成员指针或者引用,将指针所或者引用指向的类的内部实现和数据进行隐藏

目录结构:

在这里插入图片描述

Pimpl代码实现:

person类把具体实现交给realperson类

//person.h
#ifndef PERSON_H
#define PERSON_H

#include <memory>
#include <string>

class RealPerson;
class Person
{
    private:
        std::shared_ptr<RealPerson> pImpl;

    public:
        void hello() const;

    public:
        Person();
        Person(const std::string &name);
        ~Person();
};

#endif /* PERSON_H */
//person.h
#ifndef PERSON_H
#define PERSON_H

#include <memory>
#include <string>

class RealPerson;
class Person
{
    private:
        std::shared_ptr<RealPerson> pImpl;

    public:
        void hello() const;

    public:
        Person();
        Person(const std::string &name);
        ~Person();
};

#endif /* PERSON_H */
//person.cpp,注意要包含下面的头文件
#include "realperson.h"
#include "person.h"

Person::Person() : pImpl(new RealPerson()) {}
Person::Person(const std::string &name) : pImpl(new RealPerson(name)) {}
Person::~Person() {}

void Person::hello() const
{
    pImpl->hello();
}
//realperson.h
#ifndef REALPERSON_H
#define REALPERSON_H

#include <string>
#include <iostream>
#include "person.h"

class RealPerson
{
    private:
        std::string name;

    public:
        void hello() const;

    public:
        RealPerson();
        RealPerson(std::string name);
        ~RealPerson();
};

#endif /* REALPERSON_H */
//realperson.cpp
#include "realperson.h"

RealPerson::RealPerson(): name("") {}
RealPerson::RealPerson(std::string name): name(name) {}
RealPerson::~RealPerson() {}

void RealPerson::hello() const
{
    std::cout << "Hi I'm " << name << std::endl;
}
//main.cpp
#include "person.h"

int main()
{
    Person JJ("JJ");
    JJ.hello();
    return 0;
}

最后给出Makefile

CC		:= g++
C_FLAGS := -std=c++17 -Wall -Wextra

BIN		:= bin
SRC		:= src
INCLUDE	:= include
LIB		:= lib

LIBRARIES	:=

EXECUTABLE	:= main

all: $(BIN)/$(EXECUTABLE)

clean:
	$(RM) $(BIN)/$(EXECUTABLE)

run: all
	./$(BIN)/$(EXECUTABLE)

$(BIN)/$(EXECUTABLE): $(SRC)/*
	$(CC) $(C_FLAGS) -I$(INCLUDE) -L$(LIB) $^ -o $@ $(LIBRARIES)

方法三:抽象类

抽象类利用工厂函数,把具体实现交给派生类

目录结构

[

代码

//person.h
#ifndef PERSON_H
#define PERSON_H

#include <memory>
#include <string>

class Male;
class Female;
class Person
{
    public:
        static std::shared_ptr<Person> create(std::string sex);
        //可以有更多create或其它函数...

    public:
        virtual void hello() = 0;

    public:
        Person();
        virtual ~Person();
};
#endif /* PERSON_H */
//person.cpp
#include "person.h"
#include "male.h"
#include "female.h"

Person::Person() {}
Person::~Person() {}

std::shared_ptr<Person> Person::create(std::string sex)
{
    if(sex == "Male")
        return std::shared_ptr<Person> (new Male());
    return std::shared_ptr<Person> (new Female());
}
//female.h
#ifndef FEMALE_H
#define FEMALE_H

#include "person.h"

class Female: public Person
{
    private:
        std::string sex = "female";
    public:
        virtual void hello();
    public:
        Female();
        virtual ~Female();
};

#endif /* FEMALE_H */
//female.cpp
#include "female.h"
#include <iostream>

Female::Female() {}
Female::~Female() {}

void Female::hello()
{
    std::cout << "Hi I'm " << this->sex << std::endl;
}
//male.h
#ifndef MALE_H
#define MALE_H

#include "person.h"

class Male : public Person
{
    private:
        std::string sex = "male";

    public:
        virtual void hello();

    public:
        Male();
        virtual ~Male();
};

#endif /* MALE_H */
//male.cpp
#include "male.h"
#include <iostream>

Male::Male() {}

Male::~Male() {}

void Male::hello()
{
    std::cout << "Hi I'm " << this->sex << std::endl;
}
//main.cpp
#include "person.h"

int main()
{
    auto p = Person::create("male");
    p->hello();
    return 0;
}

最后给出Makefile

CC		:= g++
C_FLAGS := -std=c++17 -Wall -Wextra

BIN		:= bin
SRC		:= src
INCLUDE	:= include
LIB		:= lib

LIBRARIES	:=

EXECUTABLE	:= main

all: $(BIN)/$(EXECUTABLE)

clean:
	$(RM) $(BIN)/$(EXECUTABLE)

run: all
	./$(BIN)/$(EXECUTABLE)

$(BIN)/$(EXECUTABLE): $(SRC)/*
	$(CC) $(C_FLAGS) -I$(INCLUDE) -L$(LIB) $^ -o $@ $(LIBRARIES)

总结

  • PImpl模式优点:降低模块的耦合、降低编译依赖,提高编译速度、接口与实现分离,提高接口的稳定性;在接口不变的情况下可以修改实现,在动态库中很有用,可以直接增加新的接口而不影响二进制兼容性,不影响用户使用
  • 抽象接口同样可以:降低模块的耦合、降低编译依赖;但是在动态库中增加新的接口会影响二进制兼容性,因为虚函数表要改变
发布了80 篇原创文章 · 获赞 68 · 访问量 7550

猜你喜欢

转载自blog.csdn.net/weixin_44048823/article/details/102907120
今日推荐