在C++中,如何为一个类创建两个接口?
例如,在创建类库时,我想为每个类指定一个内部API和一个公共API,因此我可以隐藏用户的一些细节。内部API将被库中的其他类使用,公共API将被库用户使用。在C++中,如何为一个类创建两个接口?
可能吗?
在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.
};
你可以使用其中任何一种,并可以使用访问说明符(公共,受保护,私有)来使你的接口公开或内部/私人!
这是我脑子里想打提交按钮后。但是,我想知道是否有另一种方式。在ActionScript中,您可以声明一个名称空间并将其用作可见性修饰符。因此,不用'public void f()',你可以做'internal void f()','f'函数只能通过'internal'命名空间来看到。 C++中是否有类似的构造? – subb 2011-03-05 19:55:17
@Subb:你可以写'public:void f()'。也就是说,每个函数之前的标记'public:'就像在ActionScript中函数之前编写'internal'一样。 (我不知道ActionScript的方式)。 – Nawaz 2011-03-05 19:58:21
我想你误会了我。实际上,您可以指定其他内容而不是公开的可见性修饰符。 – 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
。这很丑陋。
这不是pimpl的成语。你从不暴露皮条;如果你这样做,它就会失去它的全部目的。 – wilhelmtell 2011-03-05 20:04:31
如果你暴露了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;
};
我个人觉得这个设计很干净。没有向下倾倒,没有微妙的继承技巧,没有友谊名单比我的手臂长。
我认为你需要更清晰。你想做什么?像“图书馆”,“公共”和“界面”这样的抽象词在没有更多上下文的情况下意义不大。 – tenfour 2011-03-05 19:51:52
查找“平普尔”或“不透明指针”,例如http://en.wikipedia.org/wiki/Opaque_pointer – Erik 2011-03-05 19:54:16
@tenfour编辑。我希望它更清楚。 – subb 2011-03-05 20:06:10