c++ -智能指针-在模板内强制转换智能指针

C++ - Smart Pointers - Casting smart pointers inside templates

本文关键字:智能 指针 转换 c++      更新时间:2023-10-16

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

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

我有两个问题需要帮忙解决。

    如下面的代码所示,我有一个具有参数类型的类作为另一个类对象的模板。现在,当我在UserClass的构造函数(第107行)中初始化下面的类时,我得到错误,因为mBaseAcceptor是一个具有基类类型模板参数的类,但我需要做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类型的参数,并且通过存储一个委托(这是一个函数)。Ptr),我们必须用适当的参数调用函数。但是如何解决这个问题呢?

  1. 如果我用派生类在接受器类内转换处理程序,当我只传递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;
}

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<BaseClass>Acceptor<DerivedClass>中的哪一个)

为Acceptor模板定义基类,并为所有Handler类型定义另一个基类。所以你的实现将改为:

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

你的Acceptor模板将更改为:

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 .

编辑:

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

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

class Derived : public Base{};

它不会使boost::shared<Derived>继承boost::shared_ptr<Base>。所以你必须使用显式的增强强制转换,如boost::static_pointer_cast, boost::dynamic_pointer_cast