在C++中,如何为一个类创建两个接口?

问题描述:

例如,在创建类库时,我想为每个类指定一个内部API和一个公共API,因此我可以隐藏用户的一些细节。内部API将被库中的其他类使用,公共API将被库用户使用。在C++中,如何为一个类创建两个接口?

可能吗?

+0

我认为你需要更清晰。你想做什么?像“图书馆”,“公共”和“界面”这样的抽象词在没有更多上下文的情况下意义不大。 – tenfour 2011-03-05 19:51:52

+0

查找“平普尔”或“不透明指针”,例如http://en.wikipedia.org/wiki/Opaque_pointer – Erik 2011-03-05 19:54:16

+0

@tenfour编辑。我希望它更清楚。 – subb 2011-03-05 20:06:10

在C++中,接口可能意味着很多事情。这可能意味着你在派生类实现,如下面的例子纯虚函数,

class Interface 
{ 
public: 
    virtual void f() = 0 ; 
}; 

class Implementation : public Interface 
{ 
public: 
    virtual void f() {} 
}; 

-

或者,它可能意味着你的类只是公共职能:

class A 
{ 
public: 
    void f() {} //public function - an interface that the outside world can 
       //use to talk to your class. 
}; 

你可以使用其中任何一种,并可以使用访问说明符(公共,受保护,私有)来使你的接口公开或内部/私人!

+0

这是我脑子里想打提交按钮后。但是,我想知道是否有另一种方式。在ActionScript中,您可以声明一个名称空间并将其用作可见性修饰符。因此,不用'public void f()',你可以做'internal void f()','f'函数只能通过'internal'命名空间来看到。 C++中是否有类似的构造? – subb 2011-03-05 19:55:17

+0

@Subb:你可以写'public:void f()'。也就是说,每个函数之前的标记'public:'就像在ActionScript中函数之前编写'internal'一样。 (我不知道ActionScript的方式)。 – Nawaz 2011-03-05 19:58:21

+0

我想你误会了我。实际上,您可以指定其他内容而不是公开的可见性修饰符。 – subb 2011-03-05 20:04:09

种。

一些图书馆为此使用好友类/函数。每个类声明其他类作为friend■如果他们需要访问多个“公共”接口:

class Car { 
    friend class Mechanic; 
    private: 
     Engine engine; 
}; 

class Mechanic { 
    // something involving Car::engine... 
}; 

这不是很漂亮,但它的工作原理。


,可能为你工作,另一种方法是平普尔(指针到实现)成语:

class CarImpl; // declaration only 

class Car { 
    private: 
     CarImpl *impl; 
    public: 
     CarImpl *getImpl(); // doesn't strictly belong in the pimpl pattern 
     // methods that simply call the corresponding methods on impl 
}; 

内部接口可通过电话getImpl()进行访问。您可以将CarImpl声明放在明确标记为内部的头文件中,以便客户端不会访问它。例如,您可以将这些标头放在名为internal的子目录中。

明显的缺点是Car类有一堆你必须实现的微不足道的方法。


第三种方法,我不建议,就是继承:

class Car { 
    public: 
     virtual void start() = 0; 
     static Car *create(); 
}; 

而且在内部头:

class CarImpl : public Car { 
    public: 
     virtual void start(); 
}; 

Car类只公开public接口;要访问内部接口,内部代码需要向下执行CarImpl。这很丑陋。

+0

这不是pimpl的成语。你从不暴露皮条;如果你这样做,它就会失去它的全部目的。 – wilhelmtell 2011-03-05 20:04:31

+0

如果你暴露了pimpl但不是它的类型的定义,我猜,它只能击败三分之一的目的。它仍然允许有效的编译;它仍然只允许暴露部分界面;它只是不允许切换到不同的实现。 – Thomas 2011-03-05 20:05:54

我不太清楚你问什么,但如果你已经定义了一个抽象类:

class Loggable { ... }; 

你可以从它继承private LY,像这样:

class User : private Loggable { ... }; 

User类现在有Loggable的成员,但它们是私有的。

请参阅C++ FAQ lite

有许多方法可以解决这个。一个是运行时多态性:

struct widget { 
    virtual debug_info diagnose() = 0; 
    virtual void draw() = 0; 
}; 

struct window { 
    virtual void draw() = 0; 
}; 

struct view : public window, public widget { 
    void draw(); 
    debug_info diagnose(); // internal 
}; 

或者编译时多态性:

struct view { 
    void draw(); 
    debug_info diagnose(); // internal 
}; 

template<class W> 
void do_it(W window) 
{ 
    widget.draw(); 
} 

template<class W> 
void diagnose_it(W widget) 
{ 
    debug_info d = widget.diagnose(); 
} 

另一种方法是,以暴露私有成员于特定功能或类:

struct widget { 
    virtual void draw() = 0; 
}; 

struct view : public widget { 
    friend void diagnose_widget(widget w); 
    void draw(); 
private: 
    debug_info diagnose(); 
}; 

// internal 
debug_info diagnose_widget(widget w) 
{ 
    debug_info d = w.diagnose(); 
} 

A C++类有3级保护:公共,受保护和私密。公共事物对每个人都是可访问的,只对后代保护 - 然后为自己而不是其他后代 - 对于班级和其朋友是私人的。

这样的友谊是给予比公共访问类/函数,而不是一个后代更多的唯一方法,它给予完全访问权限,这并不总是很方便。

的解决方案,我已经成功使用的是写一个包装这是主类的朋友,然后提供给自己的朋友额外的访问(这是唯一一个能够构建包装)。我没有真正推荐它,这很乏味,但如果你有这样的需求,它可能会有用。

class Main { 
public: 
    ... 
private: // but wrapped 
    void foo(); 
protected: 
    ... 
private: // and not wrapped 
    void bar(); 
}; 

class Wrapper { 
pubic: 
    void foo() { wrapped.foo(); } 
private: 
    Wrapper(Main& m) : wrapped(ma) {} 
    Main& wrapped; 
    friend void qux(Main&); 
}; 

void qux(Main& m) { 
    Wrapper mwrapped(m) 

    mwrapped.foo(); 
    // still can't access bar 
} 

你可以使用很多技巧来给予友谊或给定的几个“扩展”接口,但它很快很麻烦。

到外部接口从内部接口分离的最简单方法...是有两个接口,因此两个类。

如果你看看由GoF的提出了一套设计模式的偷看,你会发现Proxy模式。

您可以通过类不暴露到库的外部,而是露出了代理,在其中包装类,并且只公开其接口的子集使用。

class MyClass 
{ 
public: 
    void foo(); 
    void bar(); 

    void printDebugInfo(); 
    void test(); 
}; 

class MyClassProxy 
{ 
public: 
    MyClassProxy(std::unique_ptr<MyClass> ptr): _ptr(ptr) {} 

    void foo() { _ptr->foo(); } 
    void bar() { _ptr->bar(); } 

private: 
    std::unique_ptr<MyClass> _ptr; 
}; 

我个人觉得这个设计很干净。没有向下倾倒,没有微妙的继承技巧,没有友谊名单比我的手臂长。