我想实现一个派生类,它也应该实现一个接口,它有一个基类可以调用的函数。下面给出了一个警告,因为将this指针传递给基类构造函数是不安全的:
struct IInterface
{
void FuncToCall() = 0;
};
struct Base
{
Base(IInterface* inter) { m_inter = inter; }
void SomeFunc() { inter->FuncToCall(); }
IInterface* m_inter;
};
struct Derived : Base, IInterface
{
Derived() : Base(this) {}
FuncToCall() {}
};
最好的方法是什么?我需要提供接口作为基础构造函数的参数,因为它并不总是作为接口的衍生类;有时它可能是一个完全不同的类。
我可以在基类SetInterface(IInterface * inter)中添加一个函数,但我想避免这种情况。
答案 0 :(得分:4)
您不会从构造函数中发布this
,因为此时您的对象尚未正确初始化。但是,在这种实际情况下,它似乎是安全的,因为您只将它发布到基类,它只存储它,并且直到稍后某个时候才会调用它,到那时构造将完成。
但是,如果要删除警告,可以使用静态工厂方法:
struct Base
{
public:
Base() { }
void setInterface(IInterface* inter) { m_inter = inter; }
void SomeFunc() { inter->FuncToCall(); }
IInterface* m_inter;
};
struct Derived : Base, IInterface
{
private:
Derived() : Base() {}
public:
static Derived* createInstance() {
Derived instance = new Derived();
instance->setInterface(instance);
return instance;
}
FuncToCall() {}
};
请注意Derived
的构造函数是私有的,以确保仅通过createInstance
进行实例化。
答案 1 :(得分:3)
您始终可以推迟界面取消引用:
struct IInterface
{
virtual ~IInterface();
virtual void FuncToCall() =0;
};
class Base
{
public:
virtual ~Base();
void SomeFunc() { GetInterface().FuncToCall(); }
private:
virtual IInterface& GetInterface() =0;
};
class Derived: public Base, public IInterface
{
public:
private:
virtual IInterface& GetInterface() { return *this; }
virtual void FuncToCall();
};
答案 2 :(得分:2)
您可以执行一组有限的操作(由标准保证),并指向尚未初始化的对象,并将其存储以供进一步使用。编译器可能会发出警告,因为很容易误用Base
中的接收指针。
请注意,除了存储之外,指针的大多数用法都是未定义的行为,但上面的代码是正确的。
答案 3 :(得分:1)
怎么样:
struct IInterface
{
void FuncToCall() = 0;
IInterface* me() { return this; }
};
...
struct Derived : IInterface, Base
{
Derived() : IInterface(), Base(me()) {}
FuncToCall() {}
};
在我们到达Base构造函数接口的时候已经初始化了,所以对me()的调用是安全的,并且没有警告
答案 4 :(得分:0)
如何将protected:
用于IInterface* m_inter;
struct IInterface
{
virtual void FuncToCall() = 0;
};
struct Base
{
Base(IInterface* inter) { m_inter = inter; }
void SomeFunc() { m_inter->FuncToCall(); }
protected: // or `public:` since you are using `struct`
IInterface* m_inter;
};
struct Derived : Base, IInterface
{
//Derived() : Base(this) {} // not good to use `this` in the initialization list
Derived() : Base() { m_inter = static_cast<IInterface*>(this); }
FuncToCall() {}
};
答案 5 :(得分:0)
有趣的是,您可以稍后通过初始化来逃避它:
Derived::Derived(): Base()
{
this->setInter(this);
}
很好,因为所有属性都已初始化。
这样您就不必改变整个设计,只是为了逃避警告。
但是,除非setInter
对某些存储空间this
不执行任何操作,否则您可能会访问未完全初始化的对象(因此存储hash
值可能会很尴尬)