构造函数

是一种特殊的函数,主要用来在创建对象时初始化对象。

定义:

  • 构造函数函数名和类名相同
  • 构造函数没有返回值类型和返回值,void 都不能写,不能 return
  • 构造函数可以重载,需要满足重载条件

之前用类里面的元素要先声明,然后调用函数初始化,用构造直接初始化

如果类对象创建是没有传递任何参数->调用无参的构造函数(类里不写任何构造函数编译器会自动创建一个无参构造函数)

构造函数在类对象创建的时候自动调用,无法在创建完成以后主动调用

#include <iostream>
#include <string>
 
class myString {
private:
	char* buffer;//buffer n.缓冲器
public:
	myString() {//无参构造函数
		buffer = new char[2];
		buffer[0] = ' ';
		buffer[1] = '\0';
	}
	myString(int count, char ch) {//没有返回值,名字和类名相同
		buffer = new char[count + 1];
		int i = 0;
		for (; i < count; i++) {
			buffer[i] = ch;
		}
		buffer[count] = '\n';
	}
	void printf() {
		std::cout << buffer << std::endl;
	}
};
 
int main(){ 
	std::string s(2, 'a');
	myString s1;
	myString s3(2, 'a');
	myString* s2 = new myString(2, 'a');
	s1.printf();
	s2->printf();
}

拷贝构造函数

拷贝构造函数是一种特殊的构造函数,是在定义一个新的对象时用自身这种类型的对象构造自身。通过同类型别的对象来初始化。
如果自己不写拷贝构造函数直接用,编译器给的拷贝构造函数是浅拷贝的。
一般拷贝构造函数都是深拷贝

myString(myString& other) {//拷贝构造函数
	buffer = new char[strlen(other.buffer)+1];
	int i = 0;//因为循环外要用到i,所以放外面
	for(; i < strlen(other.buffer); i++) {
		buffer[i] = other.buffer[i];
	}
	buffer[i] = '\0';
}

深拷贝和浅拷贝

深拷贝就是只把值拷贝过来
浅拷贝是指向同一个地址
例如:以上的拷贝构造函数就是一个深拷贝
如果是浅拷贝函数体应该这样写:buffer = other.buffer
注意这个是对于指针类型的元素,如果是其他比如 int 那只能直接写 x=other.x,是深拷贝只拷贝值

析构函数

跟构造函数类似,也是一种特殊的函数,作用是对象结束生命周期时,系统自动调用析构函数来做清理工作

定义:

  • 函数名与类名相同,在前面加上一个 类名 (){}
  • 没有返回值类型和返回值,也没有参数
  • 如果类中没有自己写析构函数,那么系统会给出一个隐式析构函数,什么也不做

this 指针

#include <iostream>
using namespace std;
 
class Person {
private:
    string name; // 成员变量
    int age;
public:
    // 场景1:解决命名冲突 (最重要、最常用的场景!)
    void setName(string name) { // 参数名和成员变量名相同
        this->name = name; // 用 this-> 明确指出,等号左边是当前对象的name
    }
 
    void setAge(int age) {
        this->age = age; // 等号左边是当前对象的age,右边是参数age
    }
 
    // 场景2:实现链式调用
    Person& growUp() {//前面这个是返回类型,返回的是类引用,是调用对象本身,如果没有		&就是一个副本
        this->age++; // 年龄+1
        return *this; // 返回对象本身,注意返回引用才能连续操作同一个对象
    }
 
    void printInfo() {
        // 其实这里编译器底层也是 cout << this->name << ...
        // 但名字不冲突时,this-> 可写可不写,通常省略
        cout << "Name: " << name << ", Age: " << age << endl;
    }
};
 
int main() {
    Person p1, p2;
 
    // 使用 setName (解决命名冲突)
    p1.setName("张三");
    p1.setAge(20);
 
    // 使用链式调用 (看起来非常流畅)
    p2.setName("李四").setAge(18).growUp(); // 连续设置并让年龄增长一岁
    p2.printInfo(); // 输出:Name: 李四, Age: 19
 
    return 0;
}
 

作用:

  1. 解决传进来的形参和类自己的成员变量重名不好分辨的问题
  2. 实现链式调用

类成员变量初始化:fileNode(int value):a(value){}