C ++ - 智能指针 - 在模板中投射智能指针

时间:2011-07-29 22:40:27

标签: c++ boost smart-pointers

我有一个复杂的代码库在工作,我创建了一个小例子来模仿问题,这是下面的代码。

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

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

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

    ./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)); 
      
    2. 然后我得到错误说

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

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

      1. 如果我在带有派生类的Acceptor类中使用Handler,那么当我只传递baseClass指针时它会工作吗?
      2. 代码

        /*
         * 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;
        }
        

3 个答案:

答案 0 :(得分:4)

Acceptor<DerivedClass>不是从Acceptor<BaseClass>派生的(DerivedClass是否从BaseClass派生并不重要)因此编译器无法将其中一个转换为另一个

我会摆脱接受者的模板化,除非你有充分的理由保留它(我在你的代码中没有看到):

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时真正做出了真正的决定(实例化一个基础或派生的处理程序)(因为你选择了你想要的Acceptor<BaseClass>Acceptor<DerivedClass>中的哪一个)

答案 1 :(得分:2)

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

class Derived : public Base{};

它不会使boost::shared<Derived>继承自boost::shared_ptr<Base>。 所以你必须相应地使用像boost::static_pointer_cast, boost::dynamic_pointer_cast那样的显式提升演员。

答案 2 :(得分:2)

定义Acceptor模板的基类和另一个基于所有Handler类型的类。因此,您的实施将更改为:

class IHandler {
};  

class IAcceptor {
public:
    virtual void Initialize(IHandler *) = 0;
    virtual void SetDelegate(delegate_t delegate) = 0;
};

您的接受者模板将更改为:

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;
};

您的Initialize实现将更改(确保正确处理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&lt; IAcceptor&gt;。

编辑:

根据您对第二个问题的评论,我将Handler对象作为指针而不是引用传递,并修改UserClass :: HandleDelegate方法以接受指向BaseClass(或IHandler类,如果您想要的话)的指针甚至更通用。)。