2013-03-02 82 views
0

這可能是C++編碼標準中解釋的關閉規則的一種情況,我想知道我是否正確地執行了此操作。我想知道,因爲我仍然有交換功能中的if-clause。如何正確關閉?

A永遠不會被直接實例化,它總是要麼B或獲得動態創建並通過(共享)指針均勻地處理,以ACfoo根據是否爲BC來切換並選擇操作。

class A { 
public: 
    virtual ~A(){} 
}; 

class B : public A {}; 
class C : public A {}; 

typedef std::shared_ptr<A> Aptr; 
typedef std::shared_ptr<B> Bptr; 
typedef std::shared_ptr<C> Cptr; 


template<class T> 
std::shared_ptr<T> get(const Aptr& pA) { 
    return std::dynamic_pointer_cast<T>(pA); 
} 

void foo(const Bptr& pB) { 
    std::cout << "operate on B\n"; 
} 

void foo(const Cptr& pC) { 
    std::cout << "operate on C\n"; 
} 

void foo(const Aptr& pA) { 
    if (auto x = get<B>(pA)) { 
    foo(x); 
    return; 
    } 
    if (auto x = get<C>(pA)) { 
    foo(x); 
    return; 
    } 
    assert(!"oops"); 
} 


int main() 
{ 
    Aptr pA(new C); 

    foo(pA); 
} 

我的問題是void foo(const Aptr& pA)是否可以更優雅地實現。這可能意味着沒有if。在這種情況下推薦getfoo

+0

使用虛擬功能? – GManNickG 2013-03-02 21:53:25

+0

'B'和'C'具有非常不同的界面。有些是常見的,並留在'A'中。所以,我不想通過虛擬操作。 – ritter 2013-03-02 21:55:05

+0

'B'和'C'在'foo()'旁邊仍然可以有不同的接口。 – 2013-03-02 21:59:26

回答

2

除非你另有做(如果你有他們,你的代碼沒有顯示它們)很好的理由,這似乎對我來說,通常的使用情況下,需要通過虛擬函數實現動態多態性:

class A 
{ 
public: 
    virtual ~A() {} 
    virtual void foo() = 0; 
}; 

class B : public A 
{ 
    virtual void foo() 
    { 
     std::cout << "operate on B\n"; 
    } 
}; 

class C : public A 
{ 
    virtual void foo() 
    { 
     std::cout << "operate on B\n"; 
    } 
}; 

此外,在C++ 11最好是在shared_ptr建設(同樣,除非你有很好的理由不這樣做)使用std::make_shared<>()用裸new分配:

int main() 
{ 
    Aptr pA = std::make_shared<C>(); 
    pA->foo(); 
} 

如果您有理由不使用虛函數並且更喜歡不同的非侵入式多態性,那麼您可以將Boost.Variant與boost::static_visitor結合使用。這甚至不需要BC相關。

#include <boost/variant.hpp> 
#include <memory> 
#include <iostream> 

class B /* ... */ {}; 
class C /* ... */ {}; 

// ... 
typedef std::shared_ptr<B> Bptr; 
typedef std::shared_ptr<C> Cptr; 

struct foo_visitor : boost::static_visitor<void> 
{ 
    void operator() (Bptr p) 
    { 
     std::cout << "operate on B\n"; 
    } 

    void operator() (Cptr p) 
    { 
     std::cout << "operate on C\n"; 
    } 
}; 

int main() 
{ 
    boost::variant<Bptr, Cptr> ptr; 
    ptr = std::make_shared<C>(); 

    foo_visitor v; 
    ptr.apply_visitor(v); 
} 

這種方法是非常相似,你選擇了一個,但也Boost.Variant確保你不會忘記包括每個變種會可能假設值的處理情況(在這種情況下, BptrCptr)。

1

只需使用虛擬成員函數。有沒有替代的真實的東西

class A { 
public: 
    virtual ~A(){} 
    virtual void foo() = 0; 
}; 

class B : public A { 
public: 
    virtual void foo() { 
    std::cout << "operate on B\n"; 
    } 
}; 

class C : public A { 
public: 
    virtual void foo() { 
    std::cout << "operate on C\n"; 
    } 
}; 

並選擇一個很好的C++ introductory book