C ++,构造函数,析构函数

时间:2018-02-14 08:10:31

标签: c++ constructor destructor

作为一个普遍的开放性问题,可以说为什么有时会在代码中间调用析构函数?! 什么是不同的可能场景可以调用析构函数。 我想了解以下代码中的类似效果

class complex
{
private:
    double re, im;
protected:

public:
    complex()
    {
        cout << "def const  " << endl;
    }

    complex(double r, double i)
    {
        cout << "parameterized " << endl;
        re = r;
        im = i;
    }

    void setdata(double r, double i)
    {
        re = r;
        im = i;
    }

    void getdata()
    {
        cout << "enter real" << endl;
        cin >> re;
        cout << "enter im" << endl;
        cin >> im;
    }

    //there are 3(?) possible variants of addition...check
    //1st
    void add(complex c1, complex c2)
    {
        cout << "in add" << endl;
        re = c1.re + c2.re;
        im = c1.im + c2.im;
    }

    //2nd
    void add(complex c)
    {
        cout << "in add" << endl;
        re += c.re;
        im += c.im;
    }

    //3rd --- (???)
//    complex add(complex c1, complex c2)
//    {
//        complex retc;
//        retc.re = c1.re + c2.re;
//        retc.im = c1.im + c2.im;
//
//        return retc;    //this one is very weird
//    }

    void display()
    {
        cout << endl << re << " + " << im << "i" << endl;
    }

    void mul(complex c1, complex c2)
    {
        cout << "in mul" << endl;
        re = c1.re*c2.re - c1.im*c2.im;
        im = c1.re*c2.im + c1.re*c2.im;
    }

    complex mul(complex c)
    {
        cout << "in mul" << endl;
        complex retc;
        retc.re = re*c.re - im*c.im;
        retc.im = re*c.im + c.re*im;

        return retc;
    }

    ~complex()
    {
        cout << re << " + " << im << "i" << endl;
        cout << "dest" << endl;
    }
};


int main()
{
    complex c1;

    c1.getdata();
    complex c2(5, 5);

    complex c3;
    c3.add(c1, c2);    //to store the answer of c1 + c2 we need c3 object

    c3.display();
    //perform c1 + c2 * c3
    complex c4;
    c4.add(c1, c2.mul(c3));    //can not use mul(c2, c3) for c2 * c3...why???!
    cout << "ans1" << endl;
    c4.display();

    //or we can also do...
    c1.add(c2.mul(c3));    //but this will modify c1
    cout << "ans2" << endl;
    c1.display();

    return 0;
}

以下是输出

def const
enter real
1
enter im
2
parameterized
def const
in add
1 + 2i
dest
5 + 5i
dest

6 + 7i
def const
in mul
def const
in add
1 + 2i
dest
-5 + 65i
dest
6 + 7i
dest
ans1

-4 + 67i
in mul
def const
in add
-5 + 65i
dest
6 + 7i
dest
ans2

-4 + 67i
-4 + 67i
dest
6 + 7i
dest
5 + 5i
dest
-4 + 67i
dest

任何想法为什么在不知名的地方调用析构函数??

3 个答案:

答案 0 :(得分:2)

  

为什么有时会在代码中间调用析构函数?

采用以下方法进行说明:

void mul(complex c1, complex c2)
{
    cout << "in mul" << endl;
    re = c1.re*c2.re - c1.im*c2.im;
    im = c1.re*c2.im + c1.re*c2.im;
}

void add(complex c1, complex c2)
{
    cout << "in add" << endl;
    re = c1.re + c2.re;
    im = c1.im + c2.im;
}

你用:

调用它
c4.add(c1, c2.mul(c3));

add()mul()都按值接收参数。当编译器看到pass-by-value参数时,它会通过复制构造函数创建参数对象的新版本。所有类都有一个默认的复制构造函数,它将逐个分配每个字段成员。这个新版本在整个方法中使用,最后被破坏。

因此,当您使用 c3 作为参数调用 c2 中的mul()时,会从复杂对象> c3 ,当到达mul()的末尾时,它将被销毁。使用 c1 调用add()c2.mul(c3)的结果也是如此。

如果您想避免这种复制(需要时间和资源),那么您应该更改函数中传递的参数类型。具体来说,您可以通过指针或引用传递它们。问题是,这将允许在函数内部对它们进行修改:但是在传递引用的具体情况下,您可以使用const对其进行修改,这将使您获得两全其美:获得对象有效地通过,没有修改的可能性。

void mul(const complex &c1, const complex &c2)
{
    cout << "in mul" << endl;
    re = c1.re*c2.re - c1.im*c2.im;
    im = c1.re*c2.im + c1.re*c2.im;
}

void add(const complex &c1, const complex &c2)
{
    cout << "in add" << endl;
    re = c1.re + c2.re;
    im = c1.im + c2.im;
}

考虑到上述方法不会修改它们被调用的实例,它们本身也可以const

void mul(const complex &c1, const complex &c2) const
{
    cout << "in mul" << endl;
    re = c1.re*c2.re - c1.im*c2.im;
    im = c1.re*c2.im + c1.re*c2.im;
}

void add(const complex &c1, const complex &c2) const
{
    cout << "in add" << endl;
    re = c1.re + c2.re;
    im = c1.im + c2.im;
}

此外,由于这些函数不需要复杂的实例,因此它们也可以是独立的,friend函数或static方法。实际上,这是值得的另一个答案。

根据经验,当你只有一个同一个类的参数时,就像在void mul(complex c2)中一样,那可能是该类的一个成员;你将以c1.mul( c2 )的身份调用它。当你有两个参数时,如void mul(complex c1, complex c2)那么它是一个独立的函数(即,你将它调用为mul( c1, c2 ),如果你希望它包含在你的类或访问中,它可以是朋友你的类的私有成员。通常你创建这些友元函数,因为你的左边有一个另一个类(或一个基元)对象的运算符。另一个问题是独立函数应该更好地返回一个新对象而不是修改一个它的论点......正如你所看到的,它变得越来越复杂。

无论如何,这些是你的方法应该运用的签名:

class complex {
public:
// ... more things...
    void mul(complex c2);
    complex operator*(const complex &c2);
    friend complex operator*(int x, const complex &c1);
// ... more things...
};

此外,不是使用display()函数将类绑定到控制台,而是更好地重载运算符&lt;&lt;,并且您将能够将该功能与任何流一起使用。

找到complete code in IDEOne

希望这有帮助。

答案 1 :(得分:0)

在显式删除指针时,在范围变量的范围末尾和临时语句的末尾处调用析构函数。

在你的情况下

c4.add(c1, c2.mul(c3));

你需要计算c2.mul(c3)。它将创建一个新的复杂类实例。它将被保留以便添加执行,并且在调用完成后它将被销毁,因为它不再需要。

答案 2 :(得分:0)

首先请记住,您应该只关心为运行时动态创建的对象调用析构函数。对此的一个直接答案是,您需要仔细验证您的代码并找出代码中所有动态创建的对象,并确切地检查它何时超出范围,即从该对象永远不会到达的时间/区域使用任何更多,并确切地说你需要调用该对象的析构函数来清除堆内存。请记住,析构函数用于释放/清除内存,以避免内存泄漏和更好的内存管理。