简体   繁体   English

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

[英]C++ - Smart Pointers - Casting smart pointers inside templates

I have a complex code base at work, and i created a small example to mimic the problem and here is the below code. 我有一个复杂的代码库在工作,并且我创建了一个小示例来模拟该问题,这是下面的代码。

< Code below for reference> - This code is compilable if we have boost libraries and FastDelegate.h linked with the project. <以下代码供参考>-如果我们将boost库和FastDelegate.h与项目链接,则可以编译此代码。 Please let me know if you need the full compilable example project, i can email you. 如果您需要完整的可编译示例项目,请告诉我,我可以给您发送电子邮件。

I have two problems and need help resolving them. 我有两个问题,需要帮助解决。

  1. As seen below in the code, i have a class with argument type as template for another classes object. 如下面的代码所示,我有一个带有参数类型的类作为另一个类对象的模板。 Now when i initialize the class below in UserClass's constructor (Line 107) i get error because mBaseAcceptor is a class with template argument of type base Class, but i need to do mbaseAcceptor(new derivedAcceptor_t). 现在,当我在UserClass的构造函数(第107行)中初始化下面的类时,由于mBaseAcceptor是带有基类类型的模板参数的类而出现错误,但是我需要执行mbaseAcceptor(new namedAcceptor_t)。 Casting problem how to fix this? 投放问题如何解决?

Error here is 这里的错误是

./boost/smart_ptr/shared_ptr.hpp:387:9: error: comparison between distinct pointer types ‘Acceptor<DerivedClass>*’ and ‘Acceptor<BaseClass>*’ lacks a cast
  1. Another problem is in line 108, even if i magically say resolve this by using another acceptor of derived class, this is where i use that mDerivedAcceptor, in Line 108 i do 另一个问题出现在第108行中,即使我神奇地说使用派生类的另一个接受器来解决此问题,这也是我在第108行中使用那个mDerivedAcceptor的地方

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

then i get error saying 那我就说错了

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

This make sense because HandleDelegate has argument of type BaseClass and by storing a delegate(which is a func. ptr) we have to call the function with appropriate argument. 这是有道理的,因为HandleDelegate具有类型为BaseClass的参数,并且通过存储委托(这是一个函数ptr),我们必须使用适当的参数来调用该函数。 But how to fix this. 但是如何解决这个问题。

  1. If i cast Handler inside Acceptor class with derived class will it work when i only pass the baseClass pointer? 如果我在具有派生类的Acceptor类中强制转换Handler,当我仅传递baseClass指针时,它将起作用吗?

Code

/*
 * 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> is not derived from Acceptor<BaseClass> (it doesn't matter that DerivedClass is derived from BaseClass or not) so the compiler can not cast one into the other. Acceptor<DerivedClass>不是从Acceptor<BaseClass>派生的(无论DerivedClass是从BaseClass派生还是无关紧要),因此编译器无法将其中一个转换为另一个。

I would get rid of the templatization of the acceptor, unless you have a good reason to keep it (which I don't see in your code) : 我会放弃接受者的模板化,除非您有充分的理由保留它(我在您的代码中没有看到):

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

Then you don't need separate baseAcceptor_t and derivedAcceptor_t types as they both become simply Acceptor , and you can do for example : 然后,您就不需要单独的baseAcceptor_tderivedAcceptor_t类型,因为它们都变成了Acceptor ,例如

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

As far as I see the only thing you loose is the ability to pass a null pointer to the acceptor's constructor and have it create its handler itself. 据我所知,唯一让您松开的是能够将null指针传递给接受者的构造函数,并使它自己创建其处理程序。 That's a very minor loss as the real decision (instantiate a base or a derived handler) is really taken when you instantiate the Acceptor anyway (because you choose which of Acceptor<BaseClass> or Acceptor<DerivedClass> you want) 这是一个很小的损失,因为无论如何,当实例化Acceptor (因为您要选择哪个Acceptor<BaseClass>Acceptor<DerivedClass> ),实际上是真正的决定(实例化基础或派生的处理程序)。

You can try to use boost::static_pointer_cast , because even though 您可以尝试使用boost::static_pointer_cast ,因为即使

class Derived : public Base{};

it doesn't make boost::shared<Derived> inherit from boost::shared_ptr<Base> . 它不会使boost::shared<Derived>boost::shared_ptr<Base>继承。 So you have to use explicit boost cast like boost::static_pointer_cast, boost::dynamic_pointer_cast accordingly. 因此,您必须相应地使用诸如boost::static_pointer_cast, boost::dynamic_pointer_cast类的显式boost boost::static_pointer_cast, boost::dynamic_pointer_cast

Define base class for the Acceptor template and another class that will be base to all Handler types. 为Acceptor模板定义基类,并为所有Handler类型创建基类。 So your implementation will change to: 因此,您的实现将更改为:

class IHandler {
};  

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

Your Acceptor template will change to: 您的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;
};

Your implementation for Initialize will change (Make sure you handle the dynamic_cast result correctly): 您对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();
}

Finally all classes that have to be used with the Acceptor will have to be derived from IHandler. 最后,必须与Iceptor一起使用的所有类都必须从IHandler派生。

Now you can change your pointer declaration to shared_ptr< IAcceptor >. 现在,您可以将指针声明更改为shared_ptr <IAcceptor>。

EDIT: 编辑:

Based on your comment for the second issue, I would pass the Handler object as a pointer instead of a reference and modify the UserClass::HandleDelegate method to accept a pointer to the BaseClass (or the IHandler class if you want to be even more generic.). 根据您对第二个问题的评论,我将Handler对象作为指针而不是引用传递,并修改UserClass :: HandleDelegate方法以接受指向BaseClass的指针(或IHandler类,如果您想更通用) )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM