簡體   English   中英

如何在C ++中編程為接口/抽象類?

[英]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_ptrC ++ 11boost

您正在做的一切正確,只有一個例外。 您需要派生自接口,而不是將其包括為成員。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM