析构函数和构造函数

1、构造函数和析构函数为什么没有返回值?

总是由编译器来调用这些函数以确保它们被执行。如果它们有返回值,要么编译器必须知道如何处理返回值,要么就只能由客户程序员自己来显式的调用构造函数与析构函数,这样一来,安全性就被人破坏了。另外,析构函数不带任何参数,因为析构不需任何选项。

构造函数返回的应当是所构造的对象。否则,我们将无法使用临时对象初始化对象。

class C

{

public:

C(): x(0) {}

C(int i): x(i) {}

private:

int x;

};

正常情况下:C c = C();是用默认构造函数创建一个临时对象,并用这个临时对象初始化c。但是如果构造函数有返回值则用返回值去初始化,就乱套了。

即调用带参数构造函数C::C(int i)。得到的c.x便会是1。于是,语义产生了歧义。???

void f(int a) {...}  //(1)
void f(const C& a) {...} //(2)
f(C()); //(3),究竟调用谁?
对于(3),我们希望调用的是(2),但如果C::C()有int类型的返回值,那么究竟是调(1)于是,我们的重载体系,乃至整个的语法体系都会崩溃。

2、显式调用构造函数和析构函数

class A
{
public:
    A()
    {
        cout<<"构造"<<endl;
    }
    ~A()
    {
        cout<<"析构"<<endl;
    }
};
int main()
{
    A a = A();
    A *tmp = new A;
    tmp->~A();//显示调用
    delete tmp;
    return 0;
}

结果:

  构造

  构造

  析构  //这个是显示调用的析构函数

  析构  //这个是delete调用的析构函数

  析构

这有什么用?有时候,在对象的生命周期结束前,想先结束这个对象的时候就会派上用场了。直接调用析构函数并不释放对象所在的内存。

显示调用构造函数方法有两个:

第一:pMyClass->MyClass::MyClass();

第二:new(pMyClass)
MyClass();

第二种用法涉及C++ placement new 的用法。参考:http://www.cnblogs.com/luxiaoxun/archive/2012/08/10/2631812.html

显示调用构造函数有什么用?

有时候,你可能由于效率考虑要用到malloc去给类对象分配内存,因为malloc是不调用构造函数的,所以这个时候会派上用场了。

另外下面也是可以的,虽然内置类型没有构造函数。???

int* i = (int*)malloc(sizeof(int));

new (i) int();

3、拷贝(复制)构造函数为什么不能用值传递

class S
{
public:
    S(int x):a(x){ }
    S(const S st) //拷贝构造函数
    {
        a = st.a;
    }
private:
    int a;
};
int main()
{
    S s1(2);
    S s2(s1);
    return 0;
}

当给s2初始化的时候调用了s2的拷贝构造函数,由于是值传递,系统会给形参st重新申请一段空间,然后调用自身的拷贝构造函数把s1的数据成员的值传给st。当调用自身的拷贝构造函数的时候又因为是值传递,所以...

也就是说,只要调用拷贝构造函数,就会重新申请一段空间,只要重新申请一段空间,就会调用拷贝构造函数,这样一直下去就形成了一个死循环。所以拷贝构造函数一定不能是值传递。

4、构造函数/析构函数抛出异常的问题

构造函数抛出异常:

1.不建议在构造函数中抛出异常;

2.构造函数抛出异常时,析构函数将不会被执行;

如果你的对象需要撤销一些已经做了的动作(如分配了内存,打开了一个文件,或者锁定了某个信号量),这些需要被撤销的动作必须被对象内部的一个数据成员记住处理。

析构函数抛出异常:

在有两种情况下会调用析构函数。第一种是在正常情况下删除一个对象,例如对象超出了作用域或被显式地delete。第二种是异常传递的堆栈辗转开解(stack-unwinding)过程中,由异常处理系统删除一个对象。

在上述两种情况下,调用析构函数时异常可能处于激活状态也可能没有处于激活状态。遗憾的是没有办法在析构函数内部区分出这两种情况。因此在写析构函数时你必须保守地假设有异常被激活,因为如果在一个异常被激活的同时,析构函数也抛出异常,并导致程序控制权转移到析构函数外,C++将调用terminate函数。这个函数的作用正如其名字所表示的:它终止你程序的运行,而且是立即终止,甚至连局部对象都没有被释放。

概括如下:

1.析构函数不应该抛出异常;

2.当析构函数中会有一些可能发生异常时,那么就必须要把这种可能发生的异常完全封装在析构函数内部,决不能让它抛出函数之外;

3.当处理另一个异常过程中,不要从析构函数抛出异常;

每个类只有一个析构函数和一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数)。对于任意一个类A,如果不想编写上述函数,C++编译器将自动为A产生四个缺省的函数,如

A(void); // 缺省的无参数构造函数

A(const A &a); // 缺省的拷贝构造函数

~A(void); // 缺省的析构函数

A & operate =(const A &a); // 缺省的赋值函数

既然能自动生成函数,为什么还要程序员编写?

原因如下:

1)如果使用缺省的无参数构造函数缺省的析构函数,等于放弃了自主初始化清除的机会,C++发明人Stroustrup的好心好意白费了。

2缺省的拷贝构造函数缺省的赋值函数均采用位拷贝而非值拷贝的方式来实现,倘若类中含有指针变量,这两个函数注定将出错。

原文地址:https://www.cnblogs.com/Lune-Qiu/p/9332731.html

时间: 2024-10-12 21:04:09

析构函数和构造函数的相关文章

关于析构函数和构造函数何时调用的小例子

详情见C++ PrimerPlus第十章 省略其他函数,将构造函数和析构函数写出来 Stock::Stock() //default constructor{ std::cout<<"Default constructor called\n"; company="no name"; shares=0; share_val=0; total_val=0;} Stock::Stock(const std::string&co,long n,doubl

php 析构函数,构造函数

php 析构函数,构造函数 <?php /** * 测试使用的PHP操作类 * Date: 2017/7/13 * Time: 14:22 */class Test{ /** 姓名 */ public $name; /** 生日 */ public $birth; /** * 构造函数方法 __construct 它是一个魔术方法 * 它是在创建对象时被自动调用 * 一个类中有且只能有一个构造函数 * 构造函数可以带参数,这些参数通常是用来给类的属性进行初始化赋值 */ public funct

【C/C++学院】(6)构造函数/析构函数/拷贝构造函数/深copy浅copy

1.构造函数 类的初始化即为构造函数.也为:隐式的初始化. 构造函数在对象初始化的时候,自动被调用.隐式的调用. 构造函数分为三种:有参构造函数.无参构造函数.拷贝构造函数. 有参构造函数调用有三种:括号法.等号法.手工法. #include <iostream> using namespace std; class Test { private: int m_a; public: Test()//无参构造函数 { } Test(const Test &obj)//拷贝构造函数 { }

c++ 析构函数和构造函数

如果存在继承,父类的析构函数最好是虚析构函数,当Base * base = new Drive(), delete base的时候能正确析构子类 不存在虚构造函数(虚函数需要借助虚函数表,构造函数执行之前,并没有对象也就没有虚函数表) 析构函数可以是内联函数 单个参数的构造函数如果不添加explicit关键字,会定义一个隐含的类型转换(从参数的类型转换到自己):添加explicit关键字会消除这种隐含转换 隐含的函数:默认构造函数.默认析构函数.拷贝构造函数.赋值函数

C++异常与析构函数及构造函数

析构函数不要抛出异常. 构造函数可以抛出异常,但是要谨慎. 原因下面这篇文章讲的不错,转载如下: http://jarfield.iteye.com/blog/811703 写Java代码的时候,遇到错误总是喜欢抛出异常,简单实用.最近开始写C++代码,发现异常没那么简单,使用须谨慎. 翻阅了<Effective C++> <More Effective C++><Inside The C++ Object Model>的相关章节,大概弄明白了一些东东,总结在本文. 本

c++类大四个默认函数-构造函数 析构函数 拷贝构造函数 赋值构造函数

每个类只有一个析构函数和一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数).对于任意一个类A,如果不编写上述函数,C++编译器将自动为A 产生四个缺省的函数,例如: A(void);//缺省的无参数构造函数 A(const A&a);//缺省的拷贝构造函数 -A();//缺省的析构函数 A&operator=(const A &a);//缺省的赋值构造函数 1).“缺省的拷贝构造函数”和“缺省的赋值函数”均采用“位拷贝”而非“值拷贝”的方式来实现,倘

C++ struct结构体定义构造函数和析构函数,构造函数参数从VS2017平台转换到Qt5平台下构建出错,采用字符集转换函数将string类型转换为wstring,构建仍然出错!

调试win硬件驱动,需要利用VS编译的win驱动构建自己的Qt5GUI程序: 其中部分win驱动源码如下 device_file::device_file(const std::string& path, DWORD accessFlags) { h = CreateFile(path.c_str(), accessFlags, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);} 调用winAPI CreateFile函数在win中字符编

虚析构函数(√)、纯虚析构函数(√)、虚构造函数(X)

from:http://blog.csdn.net/fisher_jiang/article/details/2477577 一. 虚析构函数 我们知道,为了能够正确的调用对象的析构函数,一般要求具有层次结构的顶级类定义其析构函数为虚函数.因为在delete一个抽象类指针时候,必须要通过虚函数找到真正的析构函数. 如: class Base{public:   Base(){}   virtual ~Base(){}};class Derived: public Base{public:   D

PHP面向对象(二)--构造函数与析构函数

一.构造方法: 构造方法又称为构造函数,是对象被创建时自动调用的方法,用来完成类初始化的工作. 1.构造方法和其他函数一样,可以传递参数,可以设定参数默认值. 2.构造方法可以调用属性,也可以调用方法. 3.构造方法可以被其他方法显式调用. 构造方法的声明:使用__construct()函数表示构造方法. <?php header("Content-Type: text/html; charset=UTF-8"); class Person{ public $name ; //定