转自http://blog.csdn.net/tqtuuuu/article/details/6652144

构造函数

对于C++的构造函数,暂且将其分为以下几类:

1. 默认构造函数

2. 隐士转换构造函数

3. 拷贝构造函数

4. 其它构造函数

1. 默认构造函数表示没有任何参数的构造函数,当自定义任何构造函数以后,将不再自动创建默认构造函数,当然,默认构造函数啥也不干,程序员关心系数顿时大跌。关于默认构造函数还需要关心的一个问题是,当本类继承于另一个类(即父类),父类没有默认构造函数时,本类将自动没有构造函数,并且还必须定义至少能够支持父类初始化的构造函数。

2. 隐士转换构造函数时什么呢?它是这样一类构造函数,这类构造函数仅含有一个参数。由于C++规定,为只含有一个参数的构造函数自动定义一种隐士转换,将构造函数的参数对应数据类型的对象转换为类对象。如下面例子所示:

 class String {
String(const char *s);
}; String s = "hello friends";

其中字符串“hello friends”通过隐士转换构造函数转换为了String类对象s。这里不得不提一个关键字explicit,比较悲剧的是学了好几年C++后才知道这么一个关键字,这也充分体现了一本好书的重要性。下面来看看explicit的用法,再解释。

 class String {
explicit String(const char *s);
}; String s = "hello friends"; //编译不通过 String s("hello friends"); //编译通过

explicit仅用于构造函数,且仅用于隐士转换构造函数,其目的是禁止隐士构造函数功能。如上代码所示,当为构造函数添加explicit关键字后,String s = "hello friends"; 编译不通过。当然,此时构造函数本身还是能够正常工作的。

3. 拷贝构造函数,就是用来复制对象的一种特殊的构造函数。通过它,可以使用一个已经创建好的对象(由拷贝构造函数的参数指定)去初始化一个正准备创建的同类对象。

 class 类名
{
public:
类名(类名 &对象名);
};

如上述代码所述,拷贝构造函数只能有一个参数,并且必须是同类对象的引用。每个类都应该有一个拷贝构造函数,如果用户没有指定,将使用默认的拷贝构造函数。默认拷贝构造函数执行对象的全部内容复制,但有时需要有选择、有变化地复制。这种情况就需要显示定义拷贝构造函数,并实现为感兴趣部分的复制或者为新对象添加某些属性值。

拷贝构造函数最常见的使用方式是在类中含有指针类型属性时,因为默认的拷贝函数是按指拷贝的,即所谓的浅拷贝。这时需要显示定义拷贝构造函数,并显示地将指针从新分配内存并copy以前指向的值到新分配的内存中。

4. 其它构造函数,没什么特别的,就是前面1,2,3未包含的构造函数均属于该类。

构造函数初始化参数列表

以下情况下需要使用初始化成员列表:(待补充)

一、需要初始化的数据成员是对象的情况;

二、需要初始化const修饰的类成员;

第一种情况,如果类A中属性存在一个类B,且类B没有不带参数的构造函数,此时初始化A时也需要初始化B,所以需要初始化参数列表。当然,此种情况一般成员属性也可以通过此种方式初始化。

第二种情况,const成员属性不能复制,一旦初始化后就不能改变。

下面的例子说明构造函数初始化参数列表的使用:

 #include <iostream>
using namespace std; class B
{
public:
B(int b) {
cout<<b<<endl;
}
}; class A
{
public:
B b;
A(int a, int ci);
private:
const int ci;
//const int ci = 10; //编译错误,不能初始化
static const int cv = ; //添加static关键字后能够编译通过
int c;
}; A::A(int a, int ci):b(a),ci(ci),c() {
cout << ci << "--" << c << endl;
} int main()
{
A a(, );
return ;
}

析构函数

析构函数就与构造函数对应,在对象消亡时做一些善后处理。看下面的例子:

 #include <iostream>
using namespace std; class A
{
public:
A() {
cout << "A..." << endl;
}
~A() {
cout << "~A" <<endl;
}
}; class B : public A
{
public:
B() {
cout<<"B..."<<endl;
}
~B() {
cout<<"~B"<<endl;
}
}; int main() {
A *a = new B();
delete a; return ;
}<span style="font-family: Arial, Verdana, sans-serif; white-space: normal; background-color: rgb(255, 255, 255); ">&nbsp;</span>

编译输出:

 # ./a.out
A...
B...
~A

由此可见,在对象a消亡时,会自动调用对象A的析构函数。但是C++也太傻了吧,明明我实例化的B对象,可为啥析构时是调用A对象的析构函数呢?看delete a,由此可估计delete关键字只认a的对象,而不会变通。怎么能够这样...

virtual关键字

上面的例子显示,构造了对象B,却没有析构,这会造成啥问题呢?反正我是不清楚了。于是C++提供的virtual关键字可以解决这个问题,看下面的代码:

 #include <iostream>
using namespace std; class A
{
public:
A() {
cout << "A..." << endl;
}
virtual ~A() { //唯一区别:添加了关键字virtual
cout << "~A" <<endl;
}
}; class B : public A
{
public:
B() {
cout<<"B..."<<endl;
}
~B() {
cout<<"~B"<<endl;
}
}; int main() {
A *a = new B();
delete a; return ;
}

输出:

 # ./a.out
A...
B...
~B
~A

可见,添加virtual关键字后,确实能够解决该问题,B对象也调用了析构函数。可是这是为什么呢?

下面开始yy了,也许delete并不是那么傻,她会去虚函数表里面查看当前析构函数是否被定义为虚函数,如果是虚函数,它就会想了,那对象会不会实例化的是子类的对象呢,于是再判断是否实例化为子类对象,如果是就先调用子类的析构函数。

C++构造函数与析构函数的更多相关文章

  1. .NET 基础 一步步 一幕幕[面向对象之构造函数、析构函数]

    构造函数.析构函数 构造函数: 语法: //无参的构造函数 [访问修饰符] 函数名() :函数名必须与类名相同. //有参的构造函数 [访问修饰符] 函数名(参数列表):函数名必须与类名相同. 作用: ...

  2. 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)

    [源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...

  3. C++构造函数、析构函数与抛出异常

    [本文链接] http://www.cnblogs.com/hellogiser/p/constructor-destructor-exceptions.html [问题] 构造函数可以抛出异常么?析 ...

  4. python中的构造函数和析构函数

    python中的特殊方法,其中两个,构造函数和析构函数的作用: 比说“__init__”这个构造函数,具有初始化的作用,也就是当该类被实例化的时候就会执行该函数.那么我们就可以把要先初始化的属性放到这 ...

  5. 内存的分配VS回收&构造函数VS析构函数

    之前有一个问题一直困扰着我,就是一个变量出了作用域,我以为这个变量的内存就被回收了,其实不是这样的,昨天问了一个高手,才豁然开朗,自己在看相关代码的反汇编代码,才知道原来真是这样就.这个问题,我想简单 ...

  6. C++C++中构造函数与析构函数的调用顺序

    http://blog.csdn.net/xw13106209/article/details/6899370 1.参考文献 参考1: C++继承中构造函数.析构函数调用顺序及虚函数的动态绑定 参考2 ...

  7. php 的 构造函数 和 析构函数

    构造函数 在C++ java里的应用及其普遍,今天好好研究了一下 php 的 构造函数 和 析构函数 构造函数 和 析构函数 构造函数 void __construct ([ mixed $args ...

  8. C++-理解构造函数、析构函数执行顺序

    先初始化序列中的函数调用,如果基类构造函数为非引用传递,则引起参数的拷贝构造 再: 先类内的成员构造函数(拷贝/默认),再类的构造函数:先基类,再派生类: 本文主要说明对象创建时构造函数的执行顺序,对 ...

  9. C++学习之类的构造函数、析构函数

    在C++的类中,都会有一个或多个构造函数.一个析构函数.一个赋值运算操作符.即使我们自己定义的类中,没有显示定义它们,编译器也会声明一个默认构造函数.一个析构函数和一个赋值运算操作符.例如: //声明 ...

  10. C++的优秀特性3:构造函数和析构函数

    (转载请注明原创于潘多拉盒子) 构造函数和析构函数是C++中再熟悉不过的概念了,几乎每个了解一点C++的人都知道这两个概念是什么意思.一个对象的全部生命期中构造函数和析构函数执行的时机如下: 1. 为 ...

随机推荐

  1. eclipse一直卡住,出现 “android sdk content loader 0%” 卡住的错误分析及解决方法

    分析:这种问题之前没有遇到过,也不知道什么原因,直接去网上查询,打开www.stackoverflow.com,输入要查询问题的关键词,我们输入 “android sdk content loader ...

  2. UWP开发中的方向传感器

    在UWP开发中,我们能使用的到方向有三种: OrientationSensor下的四元数:Compass罗盘的HeadingMagneticNorth:以及SimpleOrientationSenso ...

  3. 基础学习day12--多线程一线程之间的通信和常用方法

    一.线程之间的通信 1.1.线程之间的通信方法 多个线程在处理统一资源,但是任务却不同,这时候就需要线程间通信.    等待/唤醒机制涉及的方法:    1. wait():让线程处于冻结状态,被wa ...

  4. IOS开发--常用的基本GDB命令

    gdb不是万能的,可是没有gdb却是万万不能的.这里给大家简单介绍下iOS开发中最基本的gdb命令. po po是print-object的简写,可用来打印所有NSObject对象.使用举例如下: ( ...

  5. 苹果Mac隐藏壁纸在哪里?Mac隐藏壁纸查找教程

    Mac隐藏壁纸怎么查找?Mac存不存在隐藏壁纸呢?今天小编就来解决大家的疑问,告诉大家怎么把Mac系统的隐藏壁纸找出来,并且弄能够正常的使用,小编特意写了一个详细的图文教程叫大家如何查找,使用Mac隐 ...

  6. jquery.qrcode.js 插件生成二维码

    下载地址:https://github.com/jeromeetienne/jquery-qrcode 例子: <!doctype html> <html> <head& ...

  7. java web中日期Date类型在页面中格式化显示的三种方式

    一般我们经常需要在将服务器端的Date类型,传到页面进行显示,这就涉及到一个如何格式化显示Date类型的问题,一般我们有三种方式进行: 1)在服务端使用SimpleDateFormat等类格式化成字符 ...

  8. redis客户端--jedis

    一.jedis jedis 是 redis推荐的java客户端.通过Jedis我们可以很方便地使用java代码的方式,对redis进行操作.jedis使用起来比较简单,它的操作方法与redis命令相类 ...

  9. Java读写文件方法总结

    Java读写文件方法总结 Java的读写文件方法在工作中相信有很多的用处的,本人在之前包括现在都在使用Java的读写文件方法来处理数据方面的输入输出,确实很方便.奈何我的记性实在是叫人着急,很多时候既 ...

  10. Javascript中replace()的一些用法总结

    关于定义 replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串. 关于语法 stringObject.replace(regexp/substr,repla ...