多个构造函数场景
根据实际开发场景,需要构建多个构造函数,如:
#include <iostream>
class Info
{
public:
Info() : m_iType(1), m_szName("q") {InitRest();}
Info(int iType) : m_iType(iType), m_szName("q") {InitRest();}
Info(std::string szName) : m_iType(1), m_szName(szName) {InitRest();}
private:
void InitRest(){
std::cout<<"InitRest,iType: "<<m_iType<<", szName: "<<m_szName<<std::endl;
}
int m_iType;
std::string m_szName;
};
int main()
{
Info objInfo1; //InitRest,iType: 1, szName: q
Info objInfo2(10); //InitRest,iType: 10, szName: q
Info objInfo3("UT"); //InitRest,iType: q, szName: UT
return 0;
}
3个构造函数,除了初始化列表不同,其他部分基本相同,重复代码;
C++11标椎后可以在变量声明时初始化参数,减少初始化列表;
class Info
{
public:
Info() : {InitRest();}
Info(int iType) : m_iType(iType) {InitRest();}
Info(std::string szName) : m_szName(szName) {InitRest();}
private:
void InitRest(){}
int m_iType = 1;
std::string m_szName = "q";
};
还是存在重复部分;C++11标椎后可以使用委派构造函数达成相同的目的,减少重复代码;
委派构造函数介绍
- 委派构造函数是在C++11标准对C++构造函数的一项改进。主要是为了减少重复代码和减少程序员写构造函数的时间;
- C++11的委派构造函数是在构造函数的初始化列表位置进行构造、委派的;
- 委派构造函数是将构造的任务分派给另外一个构造函数完成;
- 目标构造函数:被调用的构造函数就是目标构造函数;
- 委派构造函数:初始化列表中调用其他构造函数的是委派构造函数;
- 注意:委派构造函数不能直接使用初始化列表初始化成员变量
- 构造函数不能同时“委派”和使用初始化列表。所以委派构造函数要给变量赋初始值,初始化代码必须写在函数体内;
#include <iostream>
class Info
{
public:
Info() { InitRest(); }
Info(int iType) :Info() { m_iType = iType; } //委派给构造函数Info()
Info(std::string szName) :Info() { m_szName = szName;} //委派给构造函数Info()
//Info() :Info(“UT”) ,m_iType (2){} //编译失败
private:
void InitRest() {
std::cout << "InitRest,iType: " << m_iType << ", szName: " << m_szName << std::endl;
}
int m_iType = 1;
std::string m_szName = "q";
};
int main()
{
Info objInfo1; //InitRest,iType: 1, szName: q
Info objInfo2(10); //InitRest,iType: 1, szName: q
Info objInfo3("UT"); //InitRest,iType: 1, szName: q
return 0;
}
- 你会发现,打印出的内容还是复制之前的内容,这是因为初始化列表的调用优先于构造函数;即先调用了Info();后再调用的赋值语句(m_iType = iType;);这是一个令人容易进入的陷阱,一定要注意;
正确使用委派构造函数
- 我们通过定义一个私有目标构造函数且将初始化列表放在私有目标构造函数中,这样其他的委派构造函数就可以委托该目标函数来完成构造了。
#include <iostream>
class Info
{
public:
Info():Info(1,"q") {}
Info(int iType) :Info(iType,"q") {} //委派给私有的构造函数Info(int,std::string)
Info(std::string szName) :Info(1,szName) {} //委派给私有的构造函数Info(int,std::string)
private:
Info(int iType,std::string szName) :m_iType (iType),m_szName (szName )
{
InitRest();
}
void InitRest() {
std::cout << "InitRest,iType: " << m_iType << ", szName: " << m_szName << std::endl;
}
int m_iType;
std::string m_szName;
};
int main()
{
Info objInfo1; //InitRest,iType: 1, szName: q
Info objInfo2(10); //InitRest,iType: 10, szName: q
Info objInfo3("UT"); //InitRest,iType: 1, szName: UT
return 0;
}
- **C++11中目标构造函数的执行总是先于委派构造函数。**应该避免目标构造函数和委派构造函数中初始化同样的成员,否则可能得到一项不到的结果。
链状委派构造函数
class Info
{
public:
Info():Info(1) {} //Info()是委派构造函数,委派给了Info(int)
Info(int iType) :Info(iType,"q") {} //Info(int)既是委派构造函数,委派给了Info(int,std::string); 也是目标构造函数
Info(std::string szName) :Info(1,szName) {} Info()是委派构造函数
private:
Info(int iType,std::string szName) :m_iType (iType),m_szName (szName ){InitRest(); } //目标构造函数
void InitRest() {}
int m_iType;
std::string m_szName;
};
链状委托构造: Info()委托Info(int)进行构造,而Info(int)又委托给Info(int,std::string)进行构造。
注意避免形成委托环,形成委托环时,编译器会提示:构造函数直接或间接委托给其自身。
委托环例子:
class Info
{
public:
Info():Info(1) {} //Info()委托Info(int)
Info(int iType) :Info("q") {} //Info(int)委托Info(std::string)
Info(std::string szName) :Info(1) {} //Info(std::string)委托Info(int)
private:
int m_iType;
std::string m_szName;
};
委派构造函数的实际应用
一个很实际的应用:使用构造模板函数产生目标构造函数。
#include <list>
#include <vector>
#include <deque>
class TempleUT
{
public:
TempleUT(const std::vector<int>& v) :TempleUT(v.begin(), v.end()){}
TempleUT(const std::deque<int>& d) : TempleUT(d.begin(), d.end()){}
private:
template<class T>
TempleUT(T first, T last):l(first, last){}
private:
std::list<int> l;
};
资料主要源自:深入理解 C++11,C++11新特性解析与应用