2011-07-29 49 views
0

我在工作时有一个复杂的代码库,并且我创建了一个模拟问题的小例子,这里是下面的代码。C++ - 智能指针 - 在模板中投射智能指针

<以下代码供参考> - 如果我们有boost库和FastDelegate.h与项目链接,此代码是可编译的。如果您需要完整的可编译示例项目,请告诉我,我可以给您发邮件。

我有两个问题,需要帮助解决它们。

  1. 如下面的代码所示,我有一个类作为另一个类对象的参数类型作为模板。现在,当我在UserClass的构造函数(Line 107)中初始化下面的类时,出现错误,因为mBaseAcceptor是一个类型为base Class的模板参数的类,但是我需要执行mbaseAcceptor(new derivedAcceptor_t)。铸造问题如何解决这个问题?这里

错误是

./boost/smart_ptr/shared_ptr.hpp:387:9: error: comparison between distinct pointer types ‘Acceptor<DerivedClass>*’ and ‘Acceptor<BaseClass>*’ lacks a cast 
  1. 的另一个问题是线108,即使我奇迹般地通过派生类的另一种受体说,解决这个问题,这是我使用mDerivedAcceptor,在108行我做

    mDerivedAcceptor->SetDelegate(fastdelegate::MakeDelegate(this, &UserClass::HandleDelegate)); 
    

然后我得到错误说

"error no matching function call for HandleDelegate(DerivedClass&, bool). 

这是有意义的,因为HandleDelegate具有类型的BaseClass的,并通过存储委托(这是一个FUNC参数。 ptr),我们必须用适当的参数调用函数。但如何解决这个问题。

  1. 如果我将派生类中的Handler内部转换为Acceptor类,它将工作,当我只传递baseClass指针?

代码

/* 
* smart_pointer_1.cpp 
* 
* Created on: Jul 26, 2011 
*  Author: balaji 
*/ 
#include <algorithm> 
#include <boost/foreach.hpp> 
#include <boost/scoped_ptr.hpp> 
#include <boost/shared_ptr.hpp> 
#include "FastDelegate.h" 
#include <iostream> 
using namespace std; 

template <class Handler> 

class Acceptor { 

public: 
    typedef fastdelegate::FastDelegate1<Handler &, bool> delegate_t; 
    Acceptor(); 
    void Initialize(Handler *&handle); 
    void SetDelegate(delegate_t delegate) { mDelegate = delegate; } 

private: 
    int mValues[2]; 
    delegate_t mDelegate; 
}; 

template <class Handler> 
Acceptor<Handler>::Acceptor() 
{ 
    std::cout << "In Constructor: " << __FUNCTION__ << std::endl; 
    mValues[0] = 1; 
    mValues[1] = 2; 

} 

template <class Handler> 
void Acceptor<Handler>::Initialize(Handler *&handle){ 
    if (!handle) { 
     std::cout << __FUNCTION__ << " : created" << std::endl; 
     handle = new Handler(); 
    } else { 
     std::cout << __FUNCTION__ << " : Error exception" << std::endl; 
    } 
    if (mDelegate && mDelegate(*handle)) { 
     std::cout << "Ok Called Handle in " << __FUNCTION__ << std::endl; 
    } else { 
     std::cout << "Not Called Handle in " << __FUNCTION__ << std::endl; 
    } 

    handle->displayComputer(); 
} 

class BaseClass { 
    std::string mComputer; 
public: 
    BaseClass() { 
    std::cout << "In Base Constructor: " << __FUNCTION__ << std::endl; 
    mComputer = "Mac"; 
    } 
    virtual void displayComputer() { 
    std::cout << "Computer type is " << mComputer << std::endl; 
    } 
}; 

class DerivedClass : public BaseClass { 
    std::string mLanguage; 
public: 
    DerivedClass() { 
    std::cout << "In Derived Constructor: " << __FUNCTION__ << std::endl; 
    mLanguage = "C++"; 
    } 
    void displayComputer() { 
    std::cout << "Language is " << mLanguage << std::endl; 
    } 
}; 

class UserClass { 
public: 
    UserClass(); 
    UserClass(bool); 
    typedef Acceptor<BaseClass> baseAcceptor_t; 
    typedef Acceptor<DerivedClass> derivedAcceptor_t; 
    typedef boost::shared_ptr<BaseClass> basePtr_t; 
    void CallDelegate(BaseClass&); 

private: 
    boost::shared_ptr<baseAcceptor_t> mBaseAcceptor; 
    boost::shared_ptr<derivedAcceptor_t> mDerivedAcceptor; 
    BaseClass *mConnBasePtr; 

    bool HandleDelegate(BaseClass& baseDelegate); 
}; 

UserClass::UserClass() : mBaseAcceptor(new baseAcceptor_t) 
{ 
    std::cout << "In Constructor: " << __FUNCTION__ << std::endl; 
    mBaseAcceptor->SetDelegate(fastdelegate::MakeDelegate(this, &UserClass::HandleDelegate)); 
    mBaseAcceptor->Initialize(mConnBasePtr); 
} 

UserClass::UserClass(bool value) 
{ 
    std::cout << "In Constructor: " << __FUNCTION__ << std::endl; 
    mBaseAcceptor.reset(new derivedAcceptor_t);   // <<========== Problem Here because of improper casting 
    mBaseAcceptor->SetDelegate(fastdelegate::MakeDelegate(this, &UserClass::HandleDelegate)); // <<=== Also here because of improper type passed to MakeDelegate function ptr. Please note HandleDelegate has an argument of type BaseClass, but Acceptor is derived class 
    mBaseAcceptor->Initialize(mConnBasePtr); 
} 


bool UserClass::HandleDelegate(BaseClass& baseDelegate) 
{ 
    std::cout << "In " << __FUNCTION__ << std::endl; 
    return true; 
} 


int main() { 
    std::cout << "In function: " << __FUNCTION__ << std::endl; 
    typedef boost::shared_ptr<UserClass> userPtr_t; 

    userPtr_t user(new UserClass(true)); 

    std::cout << "In function: " << __FUNCTION__ << " at end "<< std::endl; 
    return 0; 
} 
+0

请在此处输入*相关的*代码。 SO具有出色的代码格式功能,因此让其他人可以轻松帮助您并在此处发布代码*。 – jalf

+0

@jalf - 我的坏,编辑我的文章与代码。我拥有完整代码的原因是因为它容易复制粘贴来分析问题。 – devgp

回答

2

定义Acceptor模板的基类和另一个将基于所有Handler类型的类。所以您的实现将改变为:

你的接受者模板将改变为:

template <class Handler> 
class Acceptor : public IAcceptor { 
public: 
    typedef fastdelegate::FastDelegate1<Handler &, bool> delegate_t; 
    Acceptor(); 
    void Initialize(IHandler *pVal); 
    void SetDelegate(delegate_t delegate) { mDelegate = delegate; } 
private: 
    int mValues[2]; 
    delegate_t mDelegate; 
}; 

您的初始化的实施将改变(请确保您正确处理的dynamic_cast的结果):

template <class Handler> 
void Acceptor<Handler>::Initialize(IHandler *pVal){ 
    Handler *pHandle = dynamic_cast<Handler>(pVal); //You will have to ofcourse ttake appropriate action if this cast fails. 
    if (!handle) { 
    std::cout << __FUNCTION__ << " : created" << std::endl; 
    handle = new Handler(); 
    } else { 
    std::cout << __FUNCTION__ << " : Error exception" << std::endl; 
    } 
    if (mDelegate && mDelegate(*handle)) { 
    std::cout << "Ok Called Handle in " << __FUNCTION__ << std::endl; 
    } else { 
    std::cout << "Not Called Handle in " << __FUNCTION__ << std::endl; 
    } 

    handle->displayComputer(); 
} 

最后,所有必须与Acceptor一起使用的类必须从IHandler派生。

现在您可以将指针声明更改为shared_ptr < IAcceptor>。

编辑:

基于对第二个问题的评论,我会通过Handler对象的指针,而不是参考和修改UserClass的:: HandleDelegate方法接受一个指向BaseClass的(或IHandler类,如果你想更通用。)。

+0

Thnx gr8的事情,让我试试你的想法。日Thnx。第二个问题是在初始化函数中,我调用了“if(mDelegate && mDelegate(* handle)){”这个mDelegate是通过Acceptor类的SetDelegate函数设置的。这在UserClass中被调用。这是函数“HandleDelegate”的一个委托,它有一个类型为BaseClass&的参数。因为我做mDerivedAcceptor-> SetDelegate(MakeDelegate(this,&HandleDelegate),这会引发错误,因为mDerivedAcceptor做了新的Acceptor,它将新派生类而不是基类 – devgp

+0

@devgp看看我的文章中的编辑。 – user258808

4

Acceptor<DerivedClass>不从Acceptor<BaseClass>衍生(它并不重要DerivedClassBaseClass或不衍生),因此编译器不能施放到彼此。

我会摆脱受体的模板化的,除非你有一个很好的理由,以保持它(我并不在你的代码中看到):

class Acceptor { 
public: 
    typedef fastdelegate::FastDelegate1<BaseClass &, bool> delegate_t; 
    Acceptor(); 
    void Initialize(BaseClass *handle); 
    void SetDelegate(delegate_t delegate) { mDelegate = delegate; } 

private: 
    int mValues[2]; 
    delegate_t mDelegate; 
}; 

void Acceptor::Initialize(BaseClass *handle){ 
    if (!handle) { 
     std::cout << __FUNCTION__ << " : Error exception" << std::endl; 
    } 
    if (mDelegate && mDelegate(*handle)) { 
     std::cout << "Ok Called Handle in " << __FUNCTION__ << std::endl; 
    } else { 
     std::cout << "Not Called Handle in " << __FUNCTION__ << std::endl; 
    } 

    handle->displayComputer(); 
} 

那么你就不需要单独baseAcceptor_tderivedAcceptor_t类型,它们都变得简单Acceptor,你可以做例子:我看你唯一宽松的是一个空指针传递的能力

UserClass::UserClass() : mBaseAcceptor(new Acceptor(new BaseClass))

据接受者的构造函数并让它自己创建处理程序。这是一个非常小的损失,因为真正的决定(实例化一个基地或派生处理程序)是真正实现了当你实例Acceptor反正(因为你选择了其中Acceptor<BaseClass>Acceptor<DerivedClass>你想)

+0

谢谢,但我还能如何做到这一点。如果你注意到这里唯一对我来说很重要的地方是模板 void Acceptor :: Initialize(Handler *&handle).. and void SetDelegate(delegate_t delegate){mDelegate = delegate; },因为委托函数需要派生类的参数 – devgp

+0

您是否真的必须让Acceptor成为模板?不能它将一个引用(或一个共享指针)存储到BaseClass中,并将其传递给它的构造函数? – dhenot

+0

是的,上面的代码只是我们主代码库中的一个例子。 Acceptor实际上做了很多事情,所以我仍然需要让Acceptor保持同样的状态。我想要的只是在某些条件为真时初始化派生类,并且需要将它传递给Acceptor,这比实例中引用的实际上会做更多的事情。 – devgp

2

你可以尝试使用boost::static_pointer_cast,因为即使

class Derived : public Base{}; 

它不会从boost::shared_ptr<Base>使boost::shared<Derived>继承。 因此,您必须相应地使用明确的增强投入,如boost::static_pointer_cast, boost::dynamic_pointer_cast