[英]How to program to an interface/abstract class in C++?
請考慮這樣的純虛擬類:
class Foo {
public: virtual int FooBar() = 0;
};
Java開發人員會將這種事情稱為“接口”。 通常,您然后編程到該接口,例如(不好的例子,對不起):
class Bar {
public: Foo f;
};
class Child : public Foo {
public: int FooBar() { return 1; }
};
Bar b;
b.foo = Child();
這顯然在C ++中不起作用,因為在構造時創建了類Foo的實例(但這是不可能的,因為Foo是抽象類)。
在C ++中是否有用於“編程到接口”的模式?
編輯:澄清了示例,抱歉。
如果您需要指向或引用接口(或抽象類)實現的內容,則可以使用對該接口的引用的指針:
class Bar {
public:
Bar( Foo& af ) : f( af )
{}
private:
Foo& f;
};
如果要使用引用Foo& f
,則指針Foo* f
或指向const實現的引用或指針( const Foo* f
const Foo& f
const Foo* f
),甚至指向const實現的const指針( const Foo* const f
)都取決於根據您的要求。
如果可能的話,請使用引用進行組合,其中引用的實現是從外部傳遞的(例如在我的示例中)。 如果對象更多是一個聚合並且由包含對象本身構造,則使用指針或智能指針。
更新:到目前為止,沒有人提到,如果您要分配動態實現接口的對象,則基類必須具有虛擬析構函數,否則,即使您使用智能對象,也將調用未定義的行為。指針。 並且要注意,智能指針可以派上用場,但不能解決所有問題。 您仍應牢記一些所有者層次結構,否則最終將遇到無法通過智能指針輕松解決的循環。
您的數據成員f
應被聲明為一個指針Foo
,或者甚至更好,因為一些形式智能指針到Foo
,例如shared_ptr<Foo>
。
您可以使用對Foo
的引用,但這會使事情變得復雜:您的類將需要顯式的構造函數,並且不可復制或可分配,除非您明確實現兩個成員函數。
為了像Java中一樣使用多態,您需要像Java中一樣使用指針和引用。 在Java中,所有內容都是原始類型或引用:編寫Foo f;
在Java中,您可以獲得參考。 在C ++中,您有一個對象 。
但是,與Java不同,C ++中的接口不必包含虛函數和基類。 一個很好的例子是標准庫中使用的迭代器接口。
我認為您需要繼承“接口”,而不是使用合成,不是嗎?
像這樣
class Bar: public Foo
{
private:
virtual int Bar() { /* ... */ }
};
這就是我從“程序到接口”的理解。
編輯: Ahaa,看着您的編輯,您確實需要在這里使用指針。 這是等效的C ++代碼:
class Foo {
public: virtual int Bar() = 0;
};
class Bar {
//.........v
public: Foo* f;
};
class Child : public Foo {
public: int Bar() { return 1; }
};
Bar b;
b.f = new Child();
但是然后您需要照顧為Child()
分配的新內存。 為了避免這種情況並使代碼絕對(邏輯上)等效,在這種情況下,您需要智能指針shared_ptr
( C ++ 11 , boost )
您正在做的一切正確,只有一個例外。 您需要派生自接口,而不是將其包括為成員。
class myInterface
{
virtual void foo() = 0;
}
class iHaveAnInterface: public myInterface
{
void foo();
}
void iHaveAnInterface::foo()
{
//implement
}
最好將C ++中的接口編寫為抽象基類 :無狀態類,至少包含一個純虛函數 。 具體的類是從接口類公開地派生的,並且(可選)添加狀態以實現接口。
class IFoo
{
public:
// enable deletion of implementation classes through IFoo*
virtual ~IFoo() {}
// interface
void bar()
{
// add optional pre-processing here
do_bar();
// add optional post-processing here
}
private:
// to be overridden by implementation classes
virtual void do_bar() = 0; // pure virtual
// no state here!
};
class FooImpl
:
public IFoo
{
public:
// constructors, assignment etc. to manipulate state
private:
virtual void do_bar()
{
// your implementation
}
// add your state here
};
void my_algorithm(IFoo* foo)
{
foo->bar();
}
int main()
{
IFoo* f = new FooImpl();
my_algorithm(f); // resolves to using FooImpl::do_bar()
return 0;
}
上面的代碼是基於運行時多態性和顯式接口的。 C ++中有一種使用編譯時多態和隱式接口的替代方法。 這是使用模板和奇怪的重復模板模式完成的。
請注意,我在這里使用了非虛擬接口 (NVI)慣用法: IFoo
的公共接口是非虛擬的,而實現是(純)虛擬的。 這為接口的編寫者提供了更大的靈活性,例如可以在IFoo::bar()
等內部添加日志記錄和其他檢查,而無需客戶端注意。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.