c++:对象的构造和析构

 1.构造函数

在c++中,有一种特殊的成员函数,它的名字和类名相同,没有返回值,不需要用户显示调用(也不能够显示调用),而是在创建对象时自动执行,这种特殊的成员函数就是构造函数。

#include <iostream>
using namespace std ;


class Student
{
	private: char *m_name ;
			 int m_age ;
	public:
		//声明构造函数
		Student(char *name,int age)
		{
			m_name = name ;
			m_age = age ;
			
		}
        ~Student(){}
		//声明普通成员函数
		void print()
		{
			cout << m_name << "的年龄是" << m_age << endl ;
		}

		
};

int main()
{
	Student stu1("小明",16);
		stu1.print();
    return 0 ;
}

   关于构造函数的几点说明:

      1.构造函数的名称必须和类名相同

      2.构造函数不能有返回值,即不能有return语句

      3.构造函数在定义对象时会自动执行,不需要手动调用

2.构造函数的重载和调用

   

#include <iostream>
using namespace std ;


class Test
{
	private: int m_a ;
	          int m_b ;
	public:
		Test()//无参构造函数
		{
			m_a = 1 ;
			m_b = 2 ;

			cout << "无参构造函数被调用" << endl ;
		}

		Test(int a)//有一个参数构造函数
		{
			m_a = a ;
			m_b = 0 ;

			cout << "有一个参数的构造函数被调用" << endl ;
		}

		Test(int a, int b)//有两个参数构造函数
		{
			m_a = a ;
			m_b = b ;

			cout << "有一个参数的构造函数被调用" << endl ;


		}

		void print()
		{
			cout << "a=" << m_a << ",b=" << m_b <<endl ; 

		}
		
};		
int main()
{
	Test t ;
	t.print();

	Test t1(10);
	t1.print();

	Test t2(10,20);
	t2.print();
	
	

    return 0 ;
}

   运行结果

无参构造函数被调用
a=1,b=2
有一个参数的构造函数被调用
a=10,b=0
有一个参数的构造函数被调用
a=10,b=20

3.拷贝构造函数

   形式:className(const  className &obj)

   作用:用一个现有的对象去初始化另一个对象

   调用时机:(对于上面的代码)

         Test的拷贝构造函数定义如下:

          

Test(const Test &obj)
{

    m_a = obj.m_a ;
    m_b = obj.m_b ;

    cout <<  "拷贝构造函数被调用" << endl ;
}

  (1)用一个对象去初始化另一个对象

Test t(10) ;
Test t1(t) ;
Test t2 = t1 ;
Test t3 = Test(t1) ;

   当创建对象t1 、t2、t3时都是用t进行初始化的,都会调用拷贝构造函数  

    (2) 当函数形参是一个对象时,例如:

void printT()
{
    t.print() ;
}

    通常以下面的方式调用:

Test t1(1,2)
printT(t1);

    t1在被构造的时候会调用2个参数的构造函数,之后调用printT,实参到形参的传递,实际就是一个复制的过程,这里等价于“Test t = t1” ,会调用形参的拷贝构造函数 。

     一般情况下,对象作为函数形参时最好使用引用或者对象指针,以避免调用拷贝构造函数时进行对象的复制。

(3)函数返回值是一个对象

Test func()
{
    Test t1 ;
    return t1 ;
    
}

一个类必须有构造函数,要么用户自己定义,要么编译器自动生成。一旦用户自己定义了构造函数,不管有几个,也不管形参如何,编译器都不在自动生成

 

4.析构函数 

    创建对象时系统会自动调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数来进行清理工作,如释放分配的内存,关闭打开的文件等,这个函数就是析构函数。

     析构函数也是一种特殊的成员函数,没有返回值,不需要程序员显示调用,而是在销毁对象时自动执行,析构函数的名字是在类名前加一个“~”,注意:析构偶函数没有参数,不能被重载,一个类只有一个析构函数,如果用户没有定义一个析构函数,编译器会自动生成一个默认的析构函数。

   例:

#include <iostream>
using namespace std ;


class Test
{
	private: int m_a ;
	          int m_b ;
	public:
		Test(int a,int b)
		{
			m_a = a ;
			m_b = b ;

			cout << "构造函数被调用" << endl ;
		}

		~Test()
		{

			cout << "析构函数被调用" << endl ;		
		}
		
};		
int main()
{

	Test t(1,2) ;


    return 0 ;
}

运行结果:

函数被调用
析构函数被调用

析构函数在对象被销毁时调用,而对象的销毁时机与它所在的内存区域有关,在所有函数之外创建的对象是全局对象,它和全局变量类似,位于内存分区中的全局数据库区,程序在结束执行时会调用这些对象的析构函数

在函数内部或者代码块中创建的对象是局部对象,位于栈区 ,出了当前作用域会调用这些对象的析构函数

 

5.构造函数的参数初始化列表 

   如果有一个类成员,它本身是一个类或者一个结构,而且这个成员只有一个带参数的构造函数,没有默认构造函数,这时如果要对这个类成员进行初始化,就必须调用 这个类成员的带参数的构造函数,比如:

Class A
{
    public:
            A(int a,int b)
            {
                m_a = a ;
                m_b = b ;
                

                printf("A 构造函数被调用,a = %d, b = %d\n",a,b);

            }

    private:
            int m_a ;
            int m_b ;

};


Class B

{
    private: 

            A m1 ;
            int m_c ;
            int m_d ;
           

};

类B中有类A的一个对象,但类B没有定义构造函数,所以类B中有一个默认的无参构造函数,即使如此,我们也不能按以下方式直接定义一个类B的对象。直接定义对象在编译时会报错,“类A中没有合适的默认构造函数可用”,原因是类B中有一个类A的对象m1 ,而类A不支持无参构造,所以类B无法以默认的方式去初始化m1,必须显示得调用调用类A的构造函数对m1进行初始化。

     为了有效地对m1初始化,c++引用了新的初始化成员变量的方法,就是对象初始化列表

使用方法:在函数首部和函数体之间加一个:,后面紧跟要初始化的参数,如:

B(int a ,int b ,int c,int d): m1(a,b),m_c(c)
{
    m_d = d ;
    printf("B 的构造函数被调用\n") ;

}

初始化列表可用于全部成员的初始化,也可用于部分变量的初始化

说明:1.初始化列表要优先于当前对象的构造函数先执行;

           2.子对象的初始化顺序和其在初始化列表的排列顺序无关,但和在类中的声明顺序有关,先声明的先初始化。

           3.析构函数的调用顺序和构造函数相反;

           4.参数初始化列表可以初始化const成员变量,初始化const成员变量的唯一方法就是初始化列表。

完整代码:

#include <iostream>
using namespace std ;

class A
{
    public :
     A(int a,int b)
     {
        m_a = a ;
        m_b = b ;

        printf("A 构造函数被调用,a = %d ,b = %d\n",a,b);
     }
     ~A()
     {
         printf("A 析构函数被调用,a = %d ,b = %d\n",m_a,m_b);
     }
    privateiii :
     int m_a ;
     int m_b ;
};

class B
{
    private:
        A m1 ;
        A m2 ;
        A m3 ;

        int m_c;
        int m_d;

        const int f ;
    public:
        B(int a,int b,int c,int d):m3(a,b),m2(c,d),m1(b,c),f(0)
    {
        m_c = c ;
        m_d = d ;
        cout << "B 构造函数被调用,c =" << c <<",d = " << d << endl ;
    }
        ~B()
        {
            printf("B 析构函数被调用,c = %d ,d = %d\n",m_c,m_d);
        }
        my_copy(const my_copy &p)
        {
            m_a = p.m_a ;
            m_b = p.m_b ;
            m_c = p.m_c ;
            m_d = p.m_d ;

        }
    
};

int main()
{
    B b(1,2,3,4);
      

    return 0;
}

  运行结果:

[root@localhost 201907]# ./lesson3 
A 构造函数被调用,a = 2 ,b = 3
A 构造函数被调用,a = 3 ,b = 4
A 构造函数被调用,a = 1 ,b = 2
B 构造函数被调用,c =3,d = 4
B 析构函数被调用,c = 3 ,d = 4
A 析构函数被调用,a = 1 ,b = 2
A 析构函数被调用,a = 3 ,b = 4
A 析构函数被调用,a = 2 ,b = 3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值