[英]C++ - Smart Pointers - Casting smart pointers inside templates
我有一个复杂的代码库在工作,并且我创建了一个小示例来模拟该问题,这是下面的代码。
<以下代码供参考>-如果我们将boost库和FastDelegate.h与项目链接,则可以编译此代码。 如果您需要完整的可编译示例项目,请告诉我,我可以给您发送电子邮件。
我有两个问题,需要帮助解决。
这里的错误是
./boost/smart_ptr/shared_ptr.hpp:387:9: error: comparison between distinct pointer types ‘Acceptor<DerivedClass>*’ and ‘Acceptor<BaseClass>*’ lacks a cast
另一个问题出现在第108行中,即使我神奇地说使用派生类的另一个接受器来解决此问题,这也是我在第108行中使用那个mDerivedAcceptor的地方
mDerivedAcceptor->SetDelegate(fastdelegate::MakeDelegate(this, &UserClass::HandleDelegate));
那我就说错了
"error no matching function call for HandleDelegate(DerivedClass&, bool).
这是有道理的,因为HandleDelegate具有类型为BaseClass的参数,并且通过存储委托(这是一个函数ptr),我们必须使用适当的参数来调用该函数。 但是如何解决这个问题。
码
/*
* 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_t
和derivedAcceptor_t
类型,因为它们都变成了Acceptor
,例如
UserClass::UserClass() : mBaseAcceptor(new Acceptor(new BaseClass))
据我所知,唯一让您松开的是能够将null指针传递给接受者的构造函数,并使它自己创建其处理程序。 这是一个很小的损失,因为无论如何,当实例化Acceptor
(因为您要选择哪个Acceptor<BaseClass>
或Acceptor<DerivedClass>
),实际上是真正的决定(实例化基础或派生的处理程序)。
您可以尝试使用boost::static_pointer_cast
,因为即使
class Derived : public Base{};
它不会使boost::shared<Derived>
从boost::shared_ptr<Base>
继承。 因此,您必须相应地使用诸如boost::static_pointer_cast, boost::dynamic_pointer_cast
类的显式boost boost::static_pointer_cast, boost::dynamic_pointer_cast
。
为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();
}
最后,必须与Iceptor一起使用的所有类都必须从IHandler派生。
现在,您可以将指针声明更改为shared_ptr <IAcceptor>。
编辑:
根据您对第二个问题的评论,我将Handler对象作为指针而不是引用传递,并修改UserClass :: HandleDelegate方法以接受指向BaseClass的指针(或IHandler类,如果您想更通用) )。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.