我有一个基类:
class CBase {
public:
virtual void SomeChecks() {}
CBase() {
/* Do some checks */
SomeChecks();
/* Do some more checks */
}
};
和派生类:
class CDerived : public CBase {
public:
virtual void SomeChecks() { /* Do some other checks */ }
CDerived() : CBase() {}
};
这种结构似乎有点奇怪但在我的情况下这是必需的,因为CBase做了一些检查,CDerived可以在它们之间混合一些检查。您可以将其视为在构造函数中“挂钩”函数的一种方法。 这种结构的问题在于,在构建CDerived时,首先构造了一个CBase,并且没有CDerived的意识(因此不会调用重载函数SomeChecks())。
我可以这样做:
class CBase {
public:
void Init() {
/* Do some checks */
SomeChecks();
/* Do some more checks */
}
virtual void SomeChecks() {}
CBase(bool bDoInit=true) {
if (bDoInit) { Init(); }
}
};
class CDerived : public CBase {
public:
virtual void SomeChecks() { /* Do some other checks */ }
CDerived() : CBase(false) { Init() }
};
这不是很安全,因为我希望带有false参数的构造函数受到保护,所以只有派生类才能调用它。 但是我必须创建第二个构造函数(受保护)并使其获取其他参数(可能未使用,因为在不必调用Init()时调用构造函数。)
所以我完全被困在这里。
修改 其实我想要这样的东西:
class CBase {
protected:
void Init() { /* Implementation of Init ... */ }
CBase() { /* Don't do the Init(), it is called by derived class */ }
public:
CBase() { Init(); } // Called when an object of CBase is created
};
class CDerived : public CBase {
public:
CDerived() : CBase() { Init(); }
};
在我看来,拥有相同参数的2个构造函数是不可能被保护和公开的?
答案 0 :(得分:3)
你想要的是两相结构。 C ++不提供这个作为语法结构,所以你必须自己做。
执行此操作的常用方法是使用Programmer的All-Purpose Ointment(添加另一层间接):将类包装在其他类中。该类的构造函数首先调用类的构造函数,然后调用其他初始化函数。当然,这会弄乱你的设计。
答案 1 :(得分:3)
不允许在构造函数/析构函数中调用虚方法 这背后的过程是虚拟方法调用方法的派生版本最多,如果构造函数还没有完成,那么大多数派生数据都没有被正确初始化,因此这样做可能会为使用无效对象提供机会。
您正在寻找的是PIMPL设计模式:
class CBase { ... };
class CDerived: public CBase { ... }
template<typename T>
class PIMPL
{
public:
PIMPL()
:m_data(new T)
{
// Constructor finished now do checks.
m_data->SomeChecks();
}
// Add appropriate copy/assignment/delete as required.
private:
// Use appropriate smart pointer.
std::auto_ptr<T> m_data;
};
int main()
{
PIMPL<CDerived> data;
}
答案 2 :(得分:2)
你在做一些比较奇怪的事情。
以下方法可行并且完全安全:
class CBase {
void SomeChecks() {};
public:
CBase() {
/* Do some checks */
SomeChecks();
}
};
class CDerived: public CBase{
void SomeOtherChecks() {};
public:
CDerived() {
/* Do some other checks */
SomeOtherChecks();
}
};
在此层次结构中,当构建CDerived时,首先CBase执行其SomeChecks(),然后CDerived正在执行其自己的OtherChecks()。应该是这样的。
您使SomeChecks()虚拟的事实表明允许在派生类中完全覆盖SomeChecks,而这些检查仍然必须在构造函数中执行。这通常表明架构破碎;实际上,您正试图将一些派生类的知识放在父级中,这通常是错误的。
答案 3 :(得分:1)
对此没有干净的解决方案。在输入CDerived ctor正文之前,您无法安全地调用CDerived函数。此时,CBase ctor必须已经返回。
一种解决方法可能如下:
protected: CBase(boost::function<void(*)(CBase*)> SomeChecks) {
// Base checks
SomeChecks(this); // Checks provieded by derived ctor but running on CBase member.
}
答案 4 :(得分:0)
应该设计一个类的层次结构,使得只有基类负责检查基本约束。例如,当子类必须为父类的构造函数创建一些构造函数参数时,此可能成为问题。
另一个问题,调用具有相同参数签名的另一个构造函数,可以使用'tagged constructor'技巧解决:创建模板构造函数。
struct C {
enum eConstructor { cCheck, cNoCheck };
template< eConstructor constr = cCheck > C( int i );
int positive_value;
};
template<> C::C<C:: cCheck >( int i ) : positive_value( std::max( 0, i ) ) { }
template<> C::C<C::cNoCheck>( int i ) : positive_value( i ) { }
struct CFive : public C {
CFive(): C<C::cNoCheck>(5) {}
};
答案 5 :(得分:-1)
也许这适合你:
class CBase {
public:
CBase() {
/* Do some checks */
SomeChecks();
/* Do some more checks */
}
virtual ~CBase(){} /*don't forget about this*/
virtual void SomeChecks() {}
};
class CDerived : public CBase {
public:
void SomeChecks() { //without virtual
/* Do some other checks */
CBase::SomeChecks(); //if you want checks from CBase
}
CDerived() : CBase() {}
};
CBase* fromBase = new CBase(); //checking with CBase::SomeChecks()
CBase* fromDerived = new CDerived(); //checking with CDerived::SomeChecks
CDerived* alsoDerived = new CDerived(); //checking with CDerived::SomeChecks