简体   繁体   English

C ++封装技术

[英]C++ Encapsulation Techniques

I'm trying to properly encapsulate a class A, which should only be operated on by class B. 我正在尝试正确封装一个A类,它只能由B类操作。

However, I want to inherit from class B. 但是,我想继承B班。

Having A friend B doesn't work -- friendship isn't inherited. 有一个朋友B不起作用 - 友谊不是继承的。

What's the generally accepted way of accomplish what I want, or am I making a mistake? 什么是普遍接受的完成我想要的方式,或者我犯了错误?

To give you a bit more color, class A represents a complex system's state. 为了给你更多颜色,A类代表复杂系统的状态。 It should only be modified by B, which are actions that can be applied to change class A's state. 它只应由B修改,这是可以应用于更改A类状态的动作。

It sounds like you may need to do a redesign; 听起来你可能需要重新设计; your class A represents a State, but your Class B represents a set of actions. 你的A类代表一个国家,但你的B类代表一组行动。 There's a relationship there, but it's not an inheritance relationship. 那里有一段关系,但这不是继承关系。 I'd suggest composition; 我建议组成; you want more of a HASA relationship than an ISA relationship, as far as I can tell. 据我所知,你想要更多的HASA关系而不是ISA关系。

If I understand you correctly, you want to have B and it's derivatives to have access to the internal implementation of class A, yes? 如果我理解正确,你想让B 和它的衍生物能够访问A类的内部实现,是吗?

Unfortunately, C++ does not have the concept of "internal" protection levels that languages like C# and Java posses. 不幸的是,C ++没有像C#和Java这样的语言拥有的“内部”保护级别的概念。

You can consider using the private implementation paradigm (pimpl) - also known as opaque pointers, to expose functionality within your system using public access levels, that consumers of A and B would not see. 您可以考虑使用私有实现范例 (pimpl) - 也称为不透明指针,使用公共访问级别公开系统中的功能,A和B的使用者将看不到。

I assume you want to allow descendants of B to access A directly? 我假设你想让B的后代直接访问A? If A and B are tightly coupled, you can make A a protected class definition within B itself, instead of being an independent definition. 如果A和B紧密耦合,则可以在A本身内使A成为受保护的类定义,而不是独立定义。 EG 例如

class B
{
protected:
    class A
    {
    };
};

Another idea is to create protected methods on B that delegate their actions to AEG 另一个想法是在B上创建受保护的方法,将其行动委托给AEG

class A
{
friend class B;
private:
    void DoSomething();
};

class B
{
protected:
    void DoSomething(A& a) { a.DoSomething(); }
};

The most straightforward way to do this is simply to have B contain an A: 最直接的方法是让B包含A:

class B { protected: A a_; B级{保护:A a_; }; };

Then, you can write a class C which inherits from B and is able to manipulate A. If C shouldn't be able to do arbitrary things to the A, then make the A private in B and provide protected methods in B that C can use to do approved things to the A, like so: 然后,你可以编写一个继承自B并且能够操作A的C类。如果C不能对A做任意事情,那么在B中使A成为私有并在B中提供C可以保护的方法用来做批准的东西到A,像这样:

class B { private: A a_; B级{私人:A a_; protected: void doSomethingToA(); protected:void doSomethingToA(); }; };

Keeping everything as is, the easiest thing to do is to add protected methods to B that give access to the equivalent feature of A it would need. 保持一切正常,最简单的方法是向B添加受保护的方法,以便访问其所需的A等效功能。 This opens the encapsulation to just subclasses of B. 这打开了封装到B的子类。

包含是要走的路(B类包含A类的私有成员),除非B需要覆盖A中的一些虚拟,在这种情况下私有继承是最接近的东西。

I cant see why you would want to inherit. 我不明白你为什么要继承。 Make everything in A private and friend B. B then has a member of A which it can freely manipulate. 在A私人和朋友B. B然后有一个A成员,它可以自由操纵。

The way you describe this it sounds more like composition rather than inheritance. 你描述它的方式听起来更像是构图而不是继承。 Eg 例如

class ComplexMachine {
  public:
    setState(int state);
};

class Operator {
   public:
   Operator(ComplexMachine & m) :_m(m) {};

   void drive() { _m->setState(1); }
   void turn() { _m->setState(2); }
   void stop() { _m->setState(0); }

   private:
   ComplexMachine _m;   
};

class SmoothOperator : public Operator { }

Working with the bits of information you have given: 使用您提供的一些信息:

Class B should be responsible for preserving the invariants of class A, and class B should be the only way to manipulate A. Any client - derived class or caller - should not need to know that A exists. B类应该负责保留A类的不变量,而B类应该是操纵A的唯一方法。任何客户端派生类或调用者都不应该知道A存在。

(From design POV, there's even no need for A to exist, but I have encountered enough practical reasons for such a separation that I won't hold it against you ;)) (从设计POV来看,甚至不需要 A存在,但我遇到了足够的实际原因,这种分离我不会反对你;))

This might require a lot of boilerplate code to be written, or some trickery with the interface. 这可能需要编写大量的样板代码,或者接口上的一些技巧。 eg if client should be allowed to use class A to query information but not to modify it, B could hand out a const & to the aggregated A. With a compiler supporting __declspec(property) or similar, the syntactic pain can be eased. 例如,如果允许客户端使用类A来查询信息但不允许修改它,则B可以将const发送给聚合的A.使用支持__declspec(属性)或类似的编译器,可以减轻语法上的痛苦。

From what I understand from your question, you will need some polymorphism . 根据我对你的问题的理解,你需要一些多态性 You need an abstract class A and class B inherits class A. Also, the protected keyword allows the classes that inherit to have access to certain information while at the same time deny access to anything else. 您需要一个抽象类A,B类继承A类。此外, protected关键字允许继承的类可以访问某些信息,同时拒绝访问其他任何信息。 Here is a little example: 这是一个小例子:

// dynamic allocation and polymorphism
#include <iostream>
using namespace std;

class CPolygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    virtual int area (void) =0;
    void printarea (void)
      { cout << this->area() << endl; }
  };

class CRectangle: public CPolygon {
  public:
    int area (void)
      { return (width * height); }
  };

class CTriangle: public CPolygon {
  public:
    int area (void)
      { return (width * height / 2); }
  };

int main () {
  CPolygon * ppoly1 = new CRectangle;
  CPolygon * ppoly2 = new CTriangle;
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  ppoly1->printarea();
  ppoly2->printarea();
  delete ppoly1;
  delete ppoly2;
  return 0;
}

Code taken from cplusplus.com (contains information on polymorphism and abstract classes too). 代码取自cplusplus.com (包含有关多态性和抽象类的信息)。

If you want to be sure that only B operates on A, make the instance of A private and expose a protected interface from B to its descendants. 如果您想确保只有B在A上运行,请将A实例设为私有,并将受保护的接口从B暴露给它的后代。

class A
{
  public:
    void foo() {}
};

class B
{
  private:
    A a;

  protected:
    void CallAFoo() { a.foo() };
};

class C : public B
{
    void goo() { CallAFoo(); }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM