构造函数的那些事

本文详细探讨了C++中的构造函数,包括默认构造函数、构造函数的继承以及构造函数中调用virtual函数的特殊情况。接着,介绍了拷贝构造函数的原理,澄清了关于浅拷贝和深拷贝的误解。最后,讨论了析构函数及其在继承中的行为,强调了析构函数设为virtual的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

          C++中的一个十分重要且常见的概念就是构造函数。但是里面深入的东西确实很多,而且相关的概念和知识点也比较多,今天一并整理,防止搞混淆。先说会涉及到的内容主要有:构造函数,默认构造函数,拷贝构造函数,默认拷贝构造函数,深拷贝,浅拷贝,析构函数。

         1.构造函数

          构造函数的作用是给对象的成员变量进行内存分配等初始化的工作。如果我们创建类的时候,我们没有手动添加构造函数,则编译器会给我们自动创建一个构造函数,这个就称之为默认构造函数。默认构造函数的作用和构造函数一样,也是对类的成员变量进行内存分配等初始化工作。但是,如果你手动添加了构造函数,则编译器不会创建默认构造函数。而且我们可以手动创建多个构造函数,也就是对构造函数进行重载。

       1.1构造函数的继承

      C++的继承机制是C++多态能够实现的一种基础,当son类继承parent类时,执行son类的构造函数时,调用的次序是先调用parent类的构造函数,而后调动son类的构造函数。代码示例:

    class Parent
{
public:
    Parent()
    {
        cout<<"调用父类的构造函数"<<endl;
    }
};
class Son:public Parent
{
public:
    Son()
    {
        cout<<"调用子类的构造函数"<<endl;
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    Son son;
}


输出结果为:

1.2构造函数中调用virtual函数

 如果在构造函数中调用virtual函数,会出现什么情况呢?先上代码;

class Parent
{
public:
    Parent()
    {
        Test();
    }
    Parent( Parent&temp)
    {
        a = temp.a;
        b = temp.b;
    }
    virtual void Test()
    {
        cout<<"父类test"<<endl;
    }
    void SetInput(intval1 ,int val2)
    {
        a = val2;
        b = val1;
    }
  virtual ~Parent()
    {
        cout<<"调用父类的析构函数"<<endl;
    }
public:
    int  a;
    int  b;
};
class Son:public Parent
{
public:
    Son()
    {
        Test();
    }
    void Test()
    {
        cout<<"子类test"<<endl;
    }
    ~Son()
    {
        cout<<"调用子类的析构函数"<<endl;
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    Parent *tempSon= new Son;
}


输出结果是调用了子类的Test接口,这个和Effective C++中的描述不符。同理,可以应用于析构函数。

注意:在《Effective C++》中建议构造函数和析构函数中不要调用virtual函数,原因是无法派生到子类的该接口。而实际的代码运行结果与该描述不符合。

2.拷贝构造函数

     拷贝构造函数是用作对象之间进行复制的,同样的,如果我们不手动创建拷贝构造函数,那么编译器会自动为我们创建一个默认拷贝构造函数。我们在对象之间的复制的时候,经常会调用到拷贝构造函数。代码示例:

  

  Parent temp;
    temp.SetInput(3,5);  // temp的成员变量复制为和
    Parent temp2(temp);
    cout<<"temp2的成员变量值为:a = "<<temp2.a<<"b= "<<temp2.b<<endl;

输出的结果为:

注意:网上很多地方都说拷贝构造函数使用的是浅拷贝,而不是深拷贝。经过实际测试,这个说法是错的。关于浅拷贝,做个说明,就是对象的地址拷贝,而不是真正的新开辟了内存。而深拷贝,需要开辟内存开始拷贝。

注意:默拷认贝构造函数和默认构造函数一样,都只能对成员变量进行初始化,而不能够对static变量进行初始化。因为static变量属于类,而不属于某一个具体的对象,默认的拷贝构造函数和默认构造函数只会对对象的成员变量进行初始化。

3.析构函数

    析构函数时C++中用作释放对象内存的一个函数接口,和构造函数对应的是,如果我们不手动创建析构函数,则编译器会替我们创建一个默认的析构函数。

3.1析构函数的继承

    当Paraent需要被继承时,其析构函数的执行顺序刚好和构造函数相反,先析构Son类,而后析构Paraent类。代码如下:

class Parent
{
public:
    Parent()
    {    }
    Parent( Parent&temp)
    {
        a = temp.a;
        b = temp.b;
    }
    void SetInput(intval1 ,int val2)
    {
        a = val2;
        b = val1;
    }
   ~Parent()
    {
        cout<<"调用父类的析构函数"<<endl;
    }
public:
    int  a;
    int  b;
};
class Son:public Parent
{
public:
    Son()
    {    }
    ~Son()
    {
        cout<<"调用子类的析构函数"<<endl;
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    Son tempson;
}


输出结果为:


注意:当一个类需要被继承时,一定要将该类的析构函数设置成virtual,否则会导致产生局部析构的现象。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值