我有一个这样的课程:
class A{
private:
init(const std::string& s=""){/*do something*/}
public:
A(){init();}
A(const A&){init();}
A(const std::string& s){init(s);}
};
它是否涵盖了可以调用构造函数的所有形式?
我想要做的是,任何对象创建必须首先调用init()
函数,即我需要定义所有可能被隐式或显式调用的构造函数。
答案 0 :(得分:5)
A(const A&)
一旦定义了A(A const&)
,编译器就不会合成任何其他构造函数。唯一可调用的构造函数将是您声明的构造函数。
A(A&&)
同样如此。
答案 1 :(得分:3)
听起来你对C ++构造函数有一点误解。
在特定情况下,类具有使用默认定义隐式声明的某些构造函数 。要避免不调用init()
函数的构造函数,不要求您声明这些构造函数。您可以遵循某些规则来阻止它们被隐式声明,或者您可以定义一些类内初始化,以确保默认定义执行您想要的额外初始化。
如果没有用户声明的构造函数,则默认构造函数仅隐式声明为默认值。
如果没有用户声明的移动构造函数或移动赋值运算符(当然也没有用户声明的复制构造函数),则复制构造函数仅隐式声明为默认值。
如果没有用户声明的复制构造函数,复制赋值运算符,移动构造函数,移动赋值运算符或析构函数(以及移动构造函数的默认定义是否有效),则仅隐式声明移动构造函数。
因此,您可以通过声明抑制任何其他构造函数的隐式声明的某些成员子集来确保对象构造始终调用您的init()
函数。
(This幻灯片有关于特殊成员函数隐式声明条件的方便参考。)
遵循上述规则:例如,声明此复制构造函数会禁止默认构造函数,移动构造函数和隐式声明的复制构造函数。因此,这确保了在不调用init()
成员函数的情况下不能构造此类的任何对象。
struct S {
S(S const &) { init(); }
void init() {}
};
您也可以简单地使用C ++ 11类内初始化,即使在默认定义中也可以执行,以确保为所有构造调用init()
。
struct S {
int x = init();
int init() { return 10; }
// ... whatever constructors you want to define
};
只要用户声明的构造函数没有显式初始化x
,那么所有用户声明和隐式声明的构造函数都将调用init()
。
答案 2 :(得分:1)
我有一个黑客可以做到这一点,但它并不是最明确的意图。
class A{
private:
bool init(...){...; return true; }
bool initialized = init(...);
public:
// your constructors.
};
请记住,init的参数不必依赖于构造函数的参数。
答案 3 :(得分:1)
对于这种情况,可能值得考虑使用实现继承:
class base {
protected:
base(std::string const &s="") { /* equivalent of your `init` */ }
// Or possibly use overloading:
// base() { /* whatever */ }
// base(std::string const &) { /* whatever */ }
};
class A : public base {
A(const std::string& s) : base(s) {}
A(const A&, const std::string& s) : base(s) {}
};
由于A
来自base
,A
的每个ctor都必须调用base
的构造函数。如果不使用成员初始值设定项列表来传递参数,则会使用默认参数自动调用 - 但创建A
而不调用base
ctor基本上是不可能的。
答案 4 :(得分:0)
我认为你最好定义移动构造函数A(A&&),我不确定自动生成不同编译器的构造函数的策略,尽管C ++ 11有明确的定义。