2013-03-02 129 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