赞
踩
构造函数就是定义了类的对象的初始化方式的函数,在初始化类的对象时,会被自动调用
构造函数无返回值,可以被重载(有多个构造函数,可以有多种初始化的方式,参考C++知识点4——vector与string简述)
- class A
- {
- public:
- A(int a) {cout<<"a constructor"<<endl;}
- A(){cout<<__func__<<endl;}
- ~A() {}
- };
-
- int main(int argc, char const *argv[])
- {
- A a;
- A b(10);
- return 0;
- }
注意:
注意区分下面两行代码
- A a;
- A a();
第一个是执行默认初始化,而第二个是声明了一个函数,如果将main函数中默认初始化改为第二种形式,程序不会打印构造函数中的log
- int main(int argc, char const *argv[])
- {
- A a();//仅仅是声明了一个函数,内存中并没有a对象
- A b(10);
- return 0;
- }
上述代码没有生成a对象,所以,更不能用A a()来调用其他成员
构造函数不能是const的成员函数,因为在构造函数中有可能会改变对象的成员,如果又将构造函数设为const,那么对象将无法被初始化
- class A
- {
- public:
- A() const {}
- ~A() {}
- };
如果类中没有自己定义构造函数,那么编译器会在必要的时候自动生成一个构造函数(A() {}),并且类的对象在在初始化时,执行默认初始化(用默认构造函数初始化对象)
但是,最好不要使用编译器提供的默认构造函数
- class A
- {
- public:
- int &b;
- };
-
- int main(int argc, char const *argv[])
- {
- A a;
- return 0;
- }
上述代码类中定义了一个引用,但是使用默认的构造函数并没有初始化引用,错过了引用初始化的唯一机会另外,导致程序报错,如果是类中定义了一个指针,也会造成未初始化的指针
如果想让错误消失,一种方法就是不定义引用,二是自己定义构造函数,下面代码展示了第二种办法
- class A
- {
- public:
- A():a(10), b(a){cout<<__func__<<endl;}
-
- int &b;
- int a;
- };
-
- int main(int argc, char const *argv[])
- {
- A a;
- cout<<a.b<<endl;
- return 0;
- }
冒号后面的就是初始化列表,用逗号隔开
构造函数的初始化列表与初始化顺序
尽可能使用初始化列表初始化变量,因为这是初始化成员变量的唯一机会,不要在构造函数中对成员变量进行赋值,因为有些变量无法赋值
- class A
- {
- public:
- A();
- const int a;
- };
-
- A::A()
- {
- a=10;
- cout<<__func__<<endl;
- }
-
- int main(int argc, char const *argv[])
- {
- A a;
- return 0;
- }

上述代码在编译时提示没有初始化const int,因为该成员唯一的初始化机会就是在构造函数的初始化列表中,当在构造函数中对a进行“初始化”时,其实是赋值操作,但是const变量无法重新赋值
正确做法就是将a在初始化列表中初始化
构造函数初始化成员变量的顺序是按照成员定义的顺序来初始化的
- class A
- {
- public:
- A();
- ~A() {}
- const int a;
- int b;
- int c;
- };
-
- A::A():a(10),b(5),c(1)
- {
- cout<<__func__<<endl;
- }
-
- int main(int argc, char const *argv[])
- {
- A a;
- cout<<a.a<<a.b<<a.c<<endl;
- return 0;
- }

上述代码中成员变量的初始化顺序是a,b,c(因为a最前,b次之,c最后),所以,在b初始化时,c中的值不确定,所以不能用c初始化b,将构造函数改成如下形式
- A::A():a(10),b(c),c(1)
- {
- cout<<__func__<<endl;
- }
可见,b的值是一个无效值,因为用c的无效值初始化
所以,在构造函数进行成员函数初始化时,最好不要让成员变量彼此初始化,如果必须这样,那么请注意成员函数的初始化顺序
explicit关键与构造函数
explicit关键字用来修饰构造函数,加上该关键字的构造函数不能执行隐式转换,具体例子见如下代码
- class A
- {
- public:
- /*explicit*/A(int a):mem(a) {cout<<"a constructor"<<endl;}
- A():mem(0){cout<<__func__<<endl;}
- ~A() {}
- A add(const A &one, const A & two);
- int mem;
- };
-
- A A::add(const A &one, const A & two)
- {
- A tmp;
- tmp.mem=one.mem+two.mem;
- return tmp;
- }
-
- int main(int argc, char const *argv[])
- {
- A one,two;
- one.mem=10;
- two.mem=20;
- A res1=one.add(one, two);
- cout<<res1.mem<<endl;
- A res2=one.add(10, 20);
- cout<<res2.mem<<endl;
- return 0;
- }

构造函数A(int a) 没有用explicit修饰,所以当执行第25行代码时,将10和20从int型数据隐式转化为两个类A的临时对象,并输出两次log,然后将这两个临时对象传入add函数
但是如果将构造函数A(int a)前添加explicit,那么上述代码就会报错,因为加上explicit关键字后,会防止上述过程
调用add时,提示函数匹配错误
此外,加上explicit修饰构造函数后,初始化对象只能用直接初始化,不能拷贝初始化
- class A
- {
- public:
- explicit A(int a):mem(a) {cout<<"a constructor"<<endl;}
- A():mem(0){cout<<__func__<<endl;}
- ~A() {}
- int mem;
- };
-
- int main(int argc, char const *argv[])
- {
- A one(10);
- A two=20;
- return 0;
- }
编译上述代码时,会提示转化错误
解决办法:
1.将explicit关键字去掉。2.将13行注释掉。3.使用static_cast转换,4。显式构造一个对象
解决办法3的代码
- int main(int argc, char const *argv[])
- {
- A one(10);
- A two=static_cast<A>(20);
- return 0;
- }
解决办法4的代码
- class A
- {
- public:
- explicit A(int a):mem(a) {cout<<"a constructor"<<mem<<endl;}
- A():mem(0){cout<<__func__<<endl;}
- ~A() {}
- A add(const A &one, const A & two);
- int mem;
- };
-
- A A::add(const A &one, const A & two)
- {
- cout<<__func__<<endl;
- A tmp;
- tmp.mem=one.mem+two.mem;
- return tmp;
- }
-
- int main(int argc, char const *argv[])
- {
- A res2=res2.add(A(10), A(20));//创建两个A的对象,调用顺序从右向左
- cout<<res2.mem<<endl;
- return 0;
- }

上述的输出结果为编译器优化的结果,关于编译器优化的具体内容见博客https://blog.csdn.net/davidhopper/article/details/90696200,写的很好
将上述代码关闭编译器优化的命令如下
g++ -g -fno-elide-constructors -Wall constructor.cpp
输出结果如下
其中,调用了两次拷贝构造函数,第一次是函数add返回时调用的,第二次是res2初始化的时候调用的,因为在拷贝构造函数中没有进行赋值操作,所以打印结果是mem的初始值0
如果在拷贝构造函数中添加赋值操作
mem=t.mem;
打印结果如下
上过过程的讨论见https://bbs.csdn.net/topics/396829997
参考:
《C++ Primer》
https://blog.csdn.net/davidhopper/article/details/90696200
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。