我有一个基类,我希望看起来像这样:
class B
{
// should look like: int I() { return someConst; }
virtual int I() = 0;
public B() { something(I()); }
}
要强制派生类重写I
并强制在构造每个对象时调用它。这习惯于做一些簿记,我需要知道正在构造什么类型的对象(但我将当前对象视为基类)。
这不起作用,因为C ++不允许你从构造函数中调用抽象虚函数。
有没有办法达到同样的效果?
基于this link,似乎答案是没有办法得到我想要的东西。不过它说的是:
简短的回答是:不。基类不知道它从哪个类派生出来 - 这也是一件好事。
[...]
也就是说,在构造函数Derived1 :: Derived1开始之前,该对象才正式成为Derived1的实例。
但是在我的情况下,我不想知道是什么,但将成为什么。事实上,只要我用户可以(事后)将其映射到一个类,我甚至不关心我得到什么。所以我甚至可以使用类似返回指针的东西来逃避它。
(现在回到阅读该链接)
答案 0 :(得分:7)
你不能从构造函数中调用虚方法(或者更确切地说,你可以调用它们,但是你最终会从当前构造的类中调用成员函数)。 ,问题是派生对象在那一刻还不存在。你可以做的很少,从构造函数中多态调用虚方法简直是不可能的。
您应该重新考虑您的设计 - 例如,将常量作为参数传递给构造函数。
class B
{
public:
explicit B(int i)
{
something(i);
}
};
答案 1 :(得分:0)
也许在每个派生类型上使用静态工厂方法?这是在.NET中构建异常对象(阅读:具有非常特定的初始化要求的对象)的常用方法,我已经开始欣赏它。
class Base
{
protected Base(int i)
{
// do stuff with i
}
}
class Derived : public Base
{
private Derived(int i)
: Base(i)
{
}
public Derived Create()
{
return new Derived(someConstantForThisDerivedType);
}
}
在基础构造函数中调用虚方法通常是不受欢迎的,因为您永远无法确定特定方法的行为,并且(正如其他人已经指出的那样)派生构造函数将不会被调用。
答案 2 :(得分:0)
当执行基类构造函数时,派生类尚不存在,这将无效:
class Base
{
public:
Base()
{
// Will call Base::I and not Derived::I because
// Derived does not yet exist.
something(I());
}
virtual ~Base() = 0
{
}
virtual int I() const = 0;
};
class Derived : public Base
{
public:
Derived()
: Base()
{
}
virtual ~Derived()
{
}
virtual int I() const
{
return 42;
}
};
相反,您可以将参数添加到基类构造函数:
class Base
{
public:
explicit Base(int i)
{
something(i);
}
virtual ~Base() = 0
{
}
};
class Derived : public Base
{
public:
Derived()
: Base(42)
{
}
virtual ~Derived()
{
}
};
或者如果你真的喜欢OOP,你还可以创建一些额外的类:
class Base
{
public:
class BaseConstructorArgs
{
public:
virtual ~BaseConstructorArgs() = 0
{
}
virtual int I() const = 0;
};
explicit Base(const BaseConstructorArgs& args)
{
something(args.I());
}
virtual ~Base() = 0
{
}
};
class Derived : public Base
{
public:
class DerivedConstructorArgs : public BaseConstructorArgs
{
public:
virtual ~DerivedConstructorArgs()
{
}
virtual int I() const
{
return 42;
}
};
Derived()
: Base(DerivedConstructorArgs())
{
}
virtual ~Derived()
{
}
};
答案 3 :(得分:0)
您需要的是two-phase construction。使用Universal Programmer的治疗:添加另一层间接。