你怎么做“真”封装在C ++中? [英] How do you do "true" encapsulation in C++?

查看:111
本文介绍了你怎么做“真”封装在C ++中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

封装(信息隐藏)是一个非常有用的概念,确保只有最少的细节被发布在类的API中。

Encapsulation (information hiding) is a very useful concept, ensuring that only the barest minimal details are published in the API of a class.

但我不能帮助认为C ++这样做的方式有点不足。以例如(基于摄氏度)的温度类,例如:

But I can't help thinking that the way C++ does this is a little deficient. Take, for example, a (Celsius-based) temperature class like:

class tTemp {
    private:
        double temp;
        double tempF (double);
    public:
        tTemp ();
        ~tTemp ();
        setTemp (double);
        double getTemp ();
        double getTempF ();
};

现在,这是一个非常简单的例子,但它说明了封装不完美的一点。 真实封装将隐藏所有不必要的信息,例如:

Now, that's a very simple case but it illustrates a point that the encapsulation isn't perfect. "Real" encapsulation would hide all unnecessary information such as:


  • 数据在内部维护 c> temp 变量(及其类型)。

  • 有一个内部例程用于华氏/ >
  • the fact that the data is maintained internally in the temp variable (and its type).
  • the fact that there is an internal routine for Fahrenheit/Celsius conversion.

所以,理想情况下,在我看来,类的实现者将使用上述头,但任何客户端的类将只看到公共

So, ideally, it seems to me that the implementor of the class would use the above header but any client of the class would see just the public bits.

不要误解我,我不是批评C ++,因为它符合预定的目的,阻止客户端使用但是对于更复杂的类,您可以根据私有数据和函数的名称,类型和签名轻松计算出内部细节。

Don't get me wrong, I'm not criticising C++ since it meets the stated purpose of preventing clients from using the private bits but, for more complex classes, you could easily work out internal details based on the names, types and signatures of private data and functions.

C ++如何允许实现者隐藏此信息(假设可能)?在C中,我只是使用一个不透明的类型,所以内部的细节将隐藏,但你会怎么做在C + +?

How does C++ allow implementors to hide this information (assuming it is possible)? In C, I'd simply use an opaque type so that the internal details would be hidden but how would you do that in C++?

我想我可以维护一个分离类,完全从客户端隐藏,并且只知道我自己的代码,然后在可见类中保留一个 void * 的实例(在我的代码内),但这似乎是一个相当痛苦的过程。

I suppose I could maintain an separate class, totally hidden from the client and known only to my own code, and then keep an instance of it with a void * in the visible class (casting within my code), but that seems a rather painful process. Is there an easier way in C++ to achieve the same end?

推荐答案

C ++使用称为pimpl的习语/指向实现)来隐藏实现细节。有关详情,请参阅此MSDN文章

C++ uses an idiom known as "pimpl" (private implementation / pointer to implementation) to hide implementation details. Take a look at this MSDN article for details.

简而言之,您正常地在头文件中公开您的接口。让我们以您的代码为例:

In short, you expose your interface in a header file as normal. Let's use your code as an example:

tTemp.h

class tTemp {
    private:
        class ttemp_impl; // forward declare the implementation class
        std::unique_ptr<ttemp_impl> pimpl;
    public:
        tTemp ();
       ~tTemp ();
       setTemp (double);
       double getTemp (void);
       double getTempF (void);
};

公共接口保留,但私有内部结构已被智能指针替换为私有实现类。此实现类只位于标题的相应.cpp文件中,不会公开公开。

The public interface remains, but the private internals have been replaced with a smart pointer to a private implementation class. This implementation class is located only in the header's corresponding .cpp file, it is not exposed publicly.

tTemp.cpp

tTemp.cpp

class tTemp::ttemp_impl
{
    // put your implementation details here
}

// use the pimpl as necessary from the public interface
// be sure to initialize the pimpl!
tTtemp::tTemp() : pimpl(new ttemp_impl) {}

允许您更改类的内部而不改变标题,这意味着更少的重新编译您的类的用户的额外的好处。

This also has the added advantage of allowing you to change the internals of your class without changing the header, which means less recompiling for users of your class.

对于一个完整的解决方案,如paxdiablo的前C ++ 11答案,但是 unique_ptr 而不是 void * ,你可以使用下面的。第一 ttemp.h

For a full solution as shown in paxdiablo's pre-C++11 answer, but with unique_ptr instead of void *, you can use the following. First ttemp.h:

#include <memory>
class tTemp {
public:
    tTemp();
    ~tTemp();
    void setTemp(double);
    double getTemp (void);
    double getTempF (void);

private:
    class impl;
    std::unique_ptr<impl> pimpl;
};

接下来, ttemp.cpp

#include "ttemp.h"

struct tTemp::impl {
    double temp;
    impl() { temp = 0; };
    double tempF (void) { return temp * 9 / 5 + 32; };
};

tTemp::tTemp() : pimpl (new tTemp::impl()) {};

tTemp::~tTemp() {}

void tTemp::setTemp (double t) { pimpl->temp = t; }

double tTemp::getTemp (void) { return pimpl->temp; }

double tTemp::getTempF (void) { return pimpl->tempF(); }

最后, ttemp_test.cpp

#include <iostream>
#include <cstdlib>
#include "ttemp.h"

int main (void) {
    tTemp t;
    std::cout << t.getTemp() << "C is " << t.getTempF() << "F\n";
    return 0;
}

和paxdiablo的解法一样,输出是:

And, like paxdiablo's solution, the output is:

0C is 32F

具有更多类型安全的附加优点。这个答案是C ++ 11的理想解决方案,如果你的编译器是前C ++ 11,请参见paxdiablo的回答。

with the added advantage of more type safety. This answer is the ideal solution for C++11, see paxdiablo's answer if your compiler is pre-C++11.

这篇关于你怎么做“真”封装在C ++中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆