C++:类和对象(对象特性)

本文详细介绍了C++中构造函数和析构函数的作用,它们分别用于对象的初始化和清理。构造函数在创建对象时自动调用,析构函数在对象销毁前调用。C++提供了默认构造函数、有参构造、拷贝构造等,并讨论了构造函数的调用规则。此外,还讲解了拷贝构造函数的调用时机和深拷贝与浅拷贝的区别。同时,文章提到了初始化列表、静态成员以及this指针的应用,强调了对象模型和空指针访问成员函数时的注意事项。

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

  • 对象的初始化和清理:
    • 对象的初始化和清理是两个非常重要的安全问题:
      • 一个对象或者变量没有初始状态,对其使用的后果是未知的
      • 一个对象或者变量使用完,没有及时清理,也会造成一定的安全问题

C++利用了构造函数和析构函数解决上述问题,这两个函数会被编译器自动调用,完成对象初始化和清理工作,对象初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造函数和析构函数,编译器会提供,编译器提供的构造函数与析构函数是空实现。

  • 构造函数:为对象的成员属性赋值,系统自动调用
    • 语法: 类名(){ }
      • 构造函数,没有返回值也不写 void
      • 函数名称与类名相同
      • 构造函数可以有参数,因此可以发生重载
      • 程序在调用对象时会自动调用,无需手动且只调用一次
  • 析构函数:用于对象销毁前系统自动调用,执行一些清理工作
    • 语法:~类名(){ }
      • 析构函数,没有返回值也不写 void
      • 函数名称与类名相同,在类名前加上 ~
      • 析构函数不可以有参数,因此不可以发生重载
      • 程序在对象销毁前会自动调用,无需手动且只调用一次
#include <iostream>

using namespace std;
//对象初始化与清理
class Person
{
public:
	//构造函数
	Person()
	{
		cout << "hello" << endl;
	}

	//析构函数
	~Person()
	{
		cout << "world" << endl;
	}
};


int main()
{
	Person p;
	system("pause");
	return 0;
}

  • 构造函数的分类及调用
    • 两种分类方式
      • 按参数分:有参构造和无参构造(默认构造)
      • 按类型分:普通构造和拷贝构造
        • 	//拷贝构造函数
          	Person(const Person &p)
          	{
                  //将传入的所有属性拷贝到我身上
          	}

    • 三种调用方式
      • 括号法
      • 显示法
      • 隐式转换法
        • class Person
          {
          public:
          	//无参构造函数
          	Person()
          	{
          		cout << "无参构造" << endl;
          	}
          	//有参构造
          	Person(int a)
          	{
          		cout << "有参构造" << endl;
          	}
          	//拷贝构造函数
          	Person(const Person &p)
          	{
          		cout << "拷贝构造" << endl;
          	}
          
          	//析构函数
          	~Person()
          	{
          		cout << "析构函数" << endl;
          	}
          };
          
          void test01()
          {
          	//括号法
          	Person p1;	//调用默认构造函数
          	Person p2(10);	//调用有参构造函数
          	Person p3(p2);	//调用拷贝构造函数
          	//注意事项:调用默认构造函数不要加()
          	cout << endl;
          	//显示法
          	Person p4;
          	Person p5 = Person(10);	//调用有参构造
          	Person p6 = Person(p5);	//调用拷贝构造
          	//Person(10): 匿名对象,当前执行结束,系统会立即回收匿名对象
          	//不要利用拷贝构造函数,初始化匿名对象
          
          	//隐式转换法
          	Person p7 = 10;	//相当于Person p7 = Person(10);
          	Person p8 = p7;	//相当于Person p8 = Person(p7);	
          }

  • 拷贝构造函数调用时机
    • 使用一个已经创建完毕的对象来初始化一个新对象
    • 值传递的方式给函数参数传值
    • 以值方式返回局部对象
      • class Person
        {
        public:
        	Person()
        	{
        		cout << "默认构造" << endl;
        	}
        
        	Person(int age)
        	{
        		cout << "有参构造" << endl;
        		m_Age = age;
        	}
        
        	Person(const Person &p)
        	{
        		cout << "拷贝构造" << endl;
        		m_Age = p.m_Age;
        	}
        
        	~Person()
        	{
        		cout << "析构函数" << endl;
        	}
        
        	int m_Age;
        
        };
        //使用一个已经创建完毕的对象来初始化一个新对象
        void test01()
        {
        	Person p1(20);
        	Person p2(p1);
        	cout << "p2的年龄" << "\t" << p2.m_Age << endl;
        }
        //值传递的方式给函数参数传值
        void doWork1(Person p)	
        {
        	
        }
        void test02()
        {
        	Person p;
        	doWork1(p);
        }
        //以值方式返回局部对象
        Person doWork2()
        {
        	Person p1;
        	return p1;
        }
        void test03()
        {
        	Person p = doWork2();
        }

  •  构造函数调用规则
    • 创建一个类,c++默认提供3个函数:默认构造(空实现)、拷贝构造(值拷贝)、析构函数(空实现)
    • 如果用户定义有参构造函数,c++不再提供默认无参构造函数,但是会提供默认拷贝构造函数
    • 如果用户定义拷贝构造函数,c++不会再提供其他构造函数

  • 深拷贝与浅拷贝
    • 浅拷贝:简单的赋值拷贝操作(会造成堆区内存重复释放)
    • 深拷贝:在堆区重新申请空间,进行拷贝操作(如果属性有在堆区开辟的,一定要自己提供拷贝构造函数)
      • 	Person(const Person& p)
        	{
        		m_Age = p.m_Age;
        		m_Name = p.m_Name;
        		//深拷贝
        		m_Height = new int(*p.m_Height);
        	}
        
        	~Person()
        	{
        		//将堆区开辟的数据做释放操作
        		if (m_Height != NULL)
        		{
        			delete m_Height;
        			m_Height = NULL;
        		}
        		cout << "析构函数" << endl;
        	}
        	int m_Age;
        	string m_Name;
        	int* m_Height;

  •  初始化列表
    • 作用:c++提供了初始化列表语法,用来初始化属性
    • 语法:构造函数():属性1(值1),属性2(值2)..........{}
      • class num
        {
        public:
        	//传统初始化
        	//num(int a, int b, int c)
        	//{
        	//	m_A = a;
        	//	m_B = b;
        	//	m_C = c;
        	//}
        	//初始化列表
        	num(int a, int b, int c) :m_A(a), m_B(b), m_C(c) {}
        	int m_A;
        	int m_B;
        	int m_C;
        
        };
        
        int main()
        {
        	num(30, 40, 50);
        	return 0;
        }
        .
  •  类对象作为类成员
    • c++类中的成员可以是另一个类的对象,我们称该成员为对象成员
    • 构造时先构造类对象,再构造自身,析构顺序与构造顺序相反
  • 静态成员
    • 静态成员变量
      • 所有对象共享一份数据
      • 再编译阶段分配内存
      • 类内声明,类外初始化
      • 两种访问方式:
        • 通过对象进行访问(对象 . )
        • 通过类名进行访问(类名::变量)
          • #include <iostream>
            
            using namespace std;
            
            class Person
            {
            public:
            	//静态成员变量
            	static int m_A;	//类内声明
            
            };
            int Person::m_A = 100;	//类外初始化
            int main()
            {
            	Person p1;
            	Person p2;
            	p2.m_A = 200;
            	cout << p1.m_A << endl;
            	return 0;
            }

    • 静态成员函数
      • 所有对象共享一个函数
      • 静态成员函数只能访问静态成员变量
        • #include <iostream>
          
          using namespace std;
          
          class Person
          {
          public:
          	//静态成员变量
          	static int m_A;	//类内声明
          
          	static void func()
          	{
          		m_A = 200;
          	}
          
          };
          int Person::m_A = 100;	//类外初始化
          int main()
          {
          	Person p1;
          	Person::func();
          	cout << p1.m_A << endl;
          	return 0;
          }

  • c++对象模型和this指针 
    • 在c++中,类内的成员变量和成员函数分开存储,只有非静态成员才属于类的对象上
    • this指针指向被调用的成员函数所属的对象
      • 用途:
        • 当形参和成员变量同名时,可用this指针来区分
        • 在类的非静态成员函数中返回对象本身,可使用return *this
          • #include <iostream>
            
            using namespace std;
            
            class Person
            {
            public:
            	Person(int age)
            	{
            		this->age = age;
            	}
            	int age;
            	Person& test(Person& p)
            	{
            		this->age += p.age;
            		return *this;
            	}
            };
            int main()
            {
            	Person p1(18);
            	//链式编程思想
            	p1.test(p1).test(p1).test(p1);
            	cout << p1.age << endl;
            	return 0;
            }

  • 空指针访问成员函数
    • c++中空指针也是可以调用成员函数的,但也要注意有没有用到this指针,如果用到this指针,需要加以判断保证代码的健壮性 
    • class Person
      {
      public:
      	void showClassName()
      	{
      		cout << "this is Person class" << endl;
      	}
      
      	void showPersonAge()
      	{
      		if (this == NULL)
      		{
      			return;
      		}
      		cout << "Age=" << m_Age << endl;
      	}
      	int m_Age=10;
      };
      
      void test01()
      {
      	Person* p = NULL;
      	p->showClassName();
      	//空指针访问里面的属性,访问不到
      	p->showPersonAge();
      }

  •  const修饰成员函数
    • 常函数:
      • 成员函数后加const后我们称这个函数为常函数
      • 常函数内不可修改成员属性
      • 成员属性声明时加关键字mutable后,在常函数中依然可以修改
    • 常对象
      • 声明对象前加const称该对象为常对象
      • 常对象只能调用常函数
      • class Person
        {
        public:
        	void showPerson() const	//在成员函数后加const,修饰的是this指向,让this指针的值也不可以改变
        	{
        		//m_A = 100;	//不可修改
        		m_B = 100;
        	}
        	void show()
        	{
        		m_A = 100;
        	}
        	 int m_A;
        	 mutable int m_B;
        };
        
        void test()
        {
        	const Person p;
        	p.showPerson();
        	//p.show();	//不可调用普通成员函数
        }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值