C ++ - Умные указатели - Приведение умных указателей в шаблонах - PullRequest
0 голосов
/ 30 июля 2011

У меня сложная база кода на работе, и я создал небольшой пример для имитации проблемы, и вот код ниже.

<Код ниже для справки> - Этот код компилируется, если у нас есть библиотеки повышения и FastDelegate.h, связанные с проектом. Пожалуйста, дайте мне знать, если вам нужен полный пример проекта, я могу отправить вам электронное письмо.

У меня две проблемы, и мне нужна помощь в их решении.

  1. Как видно ниже в коде, у меня есть класс с типом аргумента в качестве шаблона для другого объекта классов. Теперь, когда я инициализирую класс ниже в конструкторе UserClass (Строка 107), я получаю ошибку, потому что mBaseAcceptor - это класс с аргументом шаблона типа Base Class, но мне нужно сделать mbaseAcceptor (новый производныйAcceptor_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;
}

Ответы [ 3 ]

4 голосов
/ 30 июля 2011

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_t и derivedAcceptor_t, так как они оба становятся просто Acceptor, и вы можете сделать, например:

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

Насколько я понимаю, единственное, что вы теряете, - это возможность передать нулевой указатель в конструктор акцептора и заставить его создать свой обработчик. Это очень незначительная потеря, поскольку реальное решение (создание экземпляра базы или производного обработчика) действительно принимается, когда вы в любом случае создаете экземпляр Acceptor (потому что вы выбираете, какой из Acceptor<BaseClass> или Acceptor<DerivedClass> вы хотите)

2 голосов
/ 30 июля 2011

Определение базового класса для шаблона Acceptor и другого класса, который будет базовым для всех типов обработчиков.Таким образом, ваша реализация изменится на:

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, если вы хотите быть еще более общим.).

2 голосов
/ 30 июля 2011

Вы можете попробовать использовать boost::static_pointer_cast, потому что даже если

class Derived : public Base{};

boost::shared<Derived> не наследуется от boost::shared_ptr<Base>. Поэтому вы должны использовать явное усиление, например boost::static_pointer_cast, boost::dynamic_pointer_cast.

...