对c ++中类中typedef函数的疑问 [英] Doubts about typedef functions inside a class in c++
问题描述
假设我有一个叫做dog的类(在.h中的类声明和在。 CPP),当狗死亡时,我想调用一个函数让狗经理知道。在狗的SetFunc中,我将收到要调用的函数:
Dog.h
class Dog
{
public:
typedef void(* OndogDie)(Dog * dog);
OndogDie函数;
void SetFunc(OndogDie func);
void Die();
};
Dog.cpp
void Dog :: SetFunc(Dog :: OndogDie func)
{
function = func;
}
void Dog :: Die()
{
function(this);
}
如果我把classdef放在类Dog里面,类,它不能作为参数传递给狗类的适当回调:
Manager.h
<$ p
$ Manager $($)
void CbdogDie(Dog * dog);
};
Manager.cpp
void Manager :: CbdogDie(Dog * d)
{
// stuff
}
Manager :: Manager()
{
Dog d = Dog();
d.SetFunc(CbdogDie); (错误:类型为void(Manager :: *)的参数(Dog * d)与类型为Dog :: OndogDie的参数不兼容)
}
我已经浏览了许多教程并回答了问题,但没有一个能够帮助我找出我的代码出了什么问题。我也考虑过使用委托类型,但它只能在一个clr项目中工作。
我认为问题可能出在我放置typedef的地方功能。还有其他地方可以定义这个功能吗?如果没有解决这个问题的方法,或者至少有其他解决方案。
谢谢
CbdogDie
(在您的代码中)是一个函数成员(非静态),并且需要一个 Manager
的实例将被调用,因此它的类型与您的回调不兼容 typedef
。 与您的错误无关,但仍值得考虑:您是否不应该将调用回调的逻辑移动到 Dog
的析构函数中?在C ++中(例如与Java不同),我们知道什么时候我们的对象被销毁了。
不知道你是否可以将它应用到你的实际问题上,但这里有一些例子可以工作。
#include< iostream>
#include< string>
class Dog
{
public:
typedef void(* on_dog_die_callback_t)(const Dog&);
Dog(const std :: string& name,on_dog_die_callback_t callback):
name_(name),callback_(callback)
{
std :: clog< < 一只名为<< this-> getName()<< 出生。
}
〜Dog()
{
std :: clog<< 一只名为<< this-> getName()<< 已经死了。
if(this-> callback_)//允许NULL指针为空操作
this-> callback _(* this);
}
std :: string
getName()const
{
return this-> name_;
}
private:
std :: string name_;
on_dog_die_callback_t callback_;
};
//注意:这是一个免费的功能,不是班级成员。
void
friendly_callback(const Dog& dog)
{
std :: clog<< 我们很抱歉,<< dog.getName()<< 死了。
}
结构管理器
{
//注意:这是一个静态函数。
static void
unfriendly_callback(const Dog& dog)
{
std :: clog<< 哈哈,< dog.getName()<< 死了。
}
};
main()
{
Dog fido(Fido,friendly_callback);
狗莱卡(Leika,经理:: unfriendly_callback);
Dog waldo(Waldo,0);
}
运行此代码的输出为:
一只名为Fido的新狗诞生了。
名叫莱卡的新狗诞生了。
名为沃尔多的新狗诞生了。
名叫沃尔多的狗已经死亡。
一只名叫莱卡的狗已经死亡。
哈哈,莱卡去世了。
名为Fido的狗已经死亡。
菲多死了我们很抱歉。
请注意,我已经(不需要)将回调的签名更改为接受 const
引用一个 Dog
而不是指针。这通常会被认为是更好的风格,但如果您需要 指向任何我看不到的原因,您也可以做到这一点。
注意:如果您决定从析构函数调用回调,请注意有一些不寻常的事情需要注意:
Dog
类拥有在调用回调之前在destuructor中释放的资源,您将传递 this
指针指向一个部分被破坏的对象,并调用其上的任何成员函数都可能调用未定义的行为。
virtual
Dog
的函数成员被传递。请注意, Dog
的析构函数只会在派生类的析构函数(如果有的话)之后调用,因此它可能会处理已经部分析构的目的。只要回调只对 Dog
base感兴趣,这就好,但如果它试图访问派生类的任何成员(通过
好消息:如果你的类很简单(没有 virtual
函数,在析构函数中没有显式的资源释放),你会好的。
I need to define a function which will return an object of a class.
Suppose I have a class called dog (class declaration in .h and implementation in .cpp), and when the dog dies, I want to call a function to let the dog manager know that. In dog`s SetFunc I will receive the function to be called:
Dog.h
class Dog
{
public:
typedef void (*OndogDie)(Dog * dog);
OndogDie function;
void SetFunc(OndogDie func);
void Die();
};
Dog.cpp
void Dog::SetFunc(Dog::OndogDie func)
{
function = func;
}
void Dog::Die()
{
function(this);
}
If I put the typedef inside the class Dog, everthing works, execept the Manager class, which can`t pass as parameter a suitable callback for the dog class :
Manager.h
#include "Dog.h"
class Manager
{
public:
Manager();
void CbdogDie(Dog * dog);
};
Manager.cpp
void Manager::CbdogDie(Dog * d)
{
//stuff
}
Manager::Manager()
{
Dog d = Dog();
d.SetFunc(CbdogDie); (Error: argument of type void(Manager::*)(Dog *d) is incompatible with parameter of type "Dog::OndogDie")
}
I already looked in many tutorials, and answered questions, but none of them had helped me find out what is wrong with my code. I have also considered using the delegate type, but it only worked in an clr project.
I`m thinking that the problem might be in the place where I put the typedef function. Is there any other place to define this function ? If not is there any solution to this problem, or at least an alternative to it.
Thanks
Repeating my comment for the convenience of further readers: CbdogDie
(in your code) is a function member (non-static) and requires an instance of Manager
to be called so its type is incompatible with your callback typedef
.
Unrelated to your error but still worth consideration: Shouldn't you move the logic that invokes the callback into Dog
's destructor? In C++ (unlike Java, for example) we know when our objects are destructed.
Not sure if you can apply this to your actual problem but here are some examples that work.
#include <iostream>
#include <string>
class Dog
{
public:
typedef void (* on_dog_die_callback_t)(const Dog&);
Dog(const std::string& name, on_dog_die_callback_t callback) :
name_(name), callback_(callback)
{
std::clog << "A new dog named " << this->getName() << " is born.\n";
}
~Dog()
{
std::clog << "A dog named " << this->getName() << " has died.\n";
if (this->callback_) // allow NULL pointer for no-op
this->callback_(*this);
}
std::string
getName() const
{
return this->name_;
}
private:
std::string name_;
on_dog_die_callback_t callback_;
};
// Note: This is a free function, not a class member.
void
friendly_callback(const Dog& dog)
{
std::clog << "We are so sorry that " << dog.getName() << " died.\n";
}
struct Manager
{
// Note: This is a static function.
static void
unfriendly_callback(const Dog& dog)
{
std::clog << "Haha, " << dog.getName() << " died.\n";
}
};
int
main()
{
Dog fido("Fido", friendly_callback);
Dog leika("Leika", Manager::unfriendly_callback);
Dog waldo("Waldo", 0);
}
The output of running this code is:
A new dog named Fido is born.
A new dog named Leika is born.
A new dog named Waldo is born.
A dog named Waldo has died.
A dog named Leika has died.
Haha, Leika died.
A dog named Fido has died.
We are so sorry that Fido died.
Note that I have (without need) changed the signature of your callback to accept a const
reference to a Dog
rather than a pointer. This will generally be considered better style but if you need a pointer for whatever reason I cannot see, you can do it as well.
Notice: If you decide to invoke the callback from your destructor, be aware that there are some unusual things to watch out for:
- Invoke the callback early in your destructor. If your
Dog
class owns resources that are freed in the destuructor before the callback is invoked, you will pass athis
pointer that points to a partially destructed object and calling any member function on it will likely invoke undefined behavior. - The callback must not invoke any
virtual
function members of theDog
it is passed. Note thatDog
's destructor will only be called after the destructor of a derived class (if any) so it might deal with an already partially destructed object. As long as the callback is only interested in theDog
base, this is fine, but if it tries to access any members of the derived class (viavirtual
function calls), undefined behaviour will result.
The good news: If your class is simple (no virtual
functions, no explicit resources released in the destructor), you'll be just fine.
这篇关于对c ++中类中typedef函数的疑问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!