构造函数

  • 名字和类名相同

  • 没有返回值

  • 构造函数是用来构造对象的,构造对象时候必定调用构造函数

  • 不写构造函数,存在一个默认的构造函数,默认的构造函数是无参的,所以可以构造无参对象

  • 默认的构造函数可以删掉,通过delete来删除

  • 显式使用默认的构造函数,通过default做显示调用

  • 通常情况下,是public属性

  • 自己写了构造函数,默认的构造函数就不存在了

  • 构造函数觉得了对象的长相(构造函数无参,对象无参)

  • 构造函数:给数据成员初始化

  • 构造函数也是函数,也可以重载,也可以缺省

结构体中也可以存在构造函数:

struct chen
{
    int age;
    char* name;
    int num;
    chen(char* pname,int page)
    {age=page;name=pname;}
}

int main()
{
    chen Chen={"chen",18};  //结构体中用了构造函数,创建结构体时,就需要按照构造函数形式来创建
    cout<<Chen.name;
}
C++构造函数初始化列表
#include <iostream>
using namespace std;
class Student{
private:
    char *m_name;
    int m_age;
    float m_score;
public:
    Student(char *name, int age, float score);
    void show();
};
//采用初始化列表
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){}

本例所示,定义构造函数时并没有在函数体中对成员变量一一赋值,其函数体为空(当然也可以有其他语句),而是在函数首部与函数体之间添加了一个冒号:,后面紧跟m_name(name), m_age(age), m_score(score)语句,这个语句的意思相当于函数体内部的m_name = name; m_age = age; m_score = score;语句,也是赋值的意思。

初始化 const 成员变量

构造函数初始化列表还有一个很重要的作用,那就是初始化 const 成员变量。初始化 const 成员变量的唯一方法就是使用初始化列表。

class VLA{
private:
    const int m_len;
    int *m_arr;
public:
    VLA(int len);
};
//必须使用初始化列表来初始化 m_len
VLA::VLA(int len): m_len(len){//若是 m_len = len这样写,就是错误的
    m_arr = new int[len];
}

构造委托

也可以称为委托构造,允许一个构造函数调用另一个构造函数

为了避免无参构造时候数据未初始化,只能采用初始化参数列表调用

class chen
{
public:
    // 委托构造函数:调用另一个构造函数
    chen() : chen("") {}  // 委托构造函数,委托给带参数的构造函数
    
    // 目标构造函数:被委托的构造函数
    chen(string name) : name(name) {}  // 初始化成员变量name
private:
    string name;
};

优势:

  1. 代码复用:避免在多个构造函数中重复相同的初始化逻辑
  2. 维护性:初始化逻辑集中在一个地方,修改时只需改一次
  3. 清晰性:明确指定了构造函数之间的依赖关系

注意:

  1. 委托构造函数不能同时直接初始化成员变量,只能委托给其他构造函数
  2. 可以形成委托链(A→B→C),但不能形成循环委托(A→B→A)
  3. 构造函数委托是 C++11 引入的特性,需要编译器支持 C++11 及以上标准

深浅拷贝问题

当类中包含「动态分配的资源」(如指针指向的堆内存、文件句柄、网络连接等)时,浅拷贝会导致问题。浅拷贝会导致同一段内存重复释放

#include<iostream>
#include<cstring>
using namespace std;
class Chen
{
public:
	Chen() {};
	Chen(const char* str)
	{
		int length = strlen(str) + 1;
		name = new char[length];
		strcpy_s(name, length, str);
	}
	~Chen() 
	{
		if (name != nullptr)
		{
			delete[] name;
			name = nullptr;
		}
	}
protected:
	char* name;
};

int main()
{
	{
		Chen myself("chen");
		Chen chen = myself;//浅拷贝问题
		return 0;
	}
}

讲解: 

1. 对象创建与内存分配

Chen myself("chen");  // ① 创建对象myself
  • 调用带参构造函数 Chen(const char* str)
  • 动态分配内存:name = new char[length](假设地址为 0x1000
  • 将字符串 "chen" 复制到 0x1000 地址

2.浅拷贝发生 

Chen chen = myself;  // ② 浅拷贝(默认拷贝构造函数)

C++ 会自动生成默认拷贝构造函数,其行为是浅拷贝 :

  • 仅将 myself.name 的值(0x1000)直接复制给 chen.name
  • 此时 myself.name 和 chen.name 指向同一块内存0x1000

3. 析构函数导致重复释放

当程序执行到 main 函数的 } 时,局部对象会按创建顺序的相反顺序销毁

总结:当类中包含「动态分配的资源」(如指针指向的堆内存、文件句柄、网络连接等)时,浅拷贝会导致问题。

解决办法就是自己写拷贝函数。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐