C++ 类和对象(中)构造函数 和 析构函数

这篇具有很好参考价值的文章主要介绍了C++ 类和对象(中)构造函数 和 析构函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 上篇链接:C++ 类和对象(上)_chihiro1122的博客-CSDN博客

类的6个默认成员函数

 我们在C当中,在写一些函数的时候,比如在栈的例子:

C++ 类和对象(中)构造函数 和 析构函数

如上述例子,用C++ 返回这个栈是否为空,直接返回的话,这栈空间没有被释放,就会内存泄漏,如果我们直接释放这个栈,那么我们就拿不到这个栈是否为空的 bool 类型值。那么我们在C中就是用 一个 bool 类型变量来接收这函数返回的布尔值 ,然后再释放,最后返回这个 bool 类型变量的值。

这样做非常的麻烦,C++的祖师爷肯定也想到的这些,这就有了类当中的  6 个默认成员函数。

 我们在 上篇中提到了 空类,那么空类当中真的是什么都不存储吗,并不是。其实在空类当中,编译器会帮我们自动的去创造  6  个默认成员函数:

 其中的 构造函数和析构函数就可以帮我们自动进行 一些 如上述的初始化和 销毁的操作。

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。
C++ 类和对象(中)构造函数 和 析构函数

 构造函数

构造函数是一个特殊的函数,它的名字和类的名字相同而且在创建类的类型对象的时候调用,一保证每一个成员都有一个初始值,并且,构造函数在对象的整个生命周期当中值调用一次

 特性

 需要注意的是,虽然构造函数是帮助对象当中的成员初始化,但是仅仅只是初始化,并不是给这个成员创建空间。

 其特性如下:

  • 构造函数名和类名一样
  • 没有返回值,也不需要 如 void 这样规定返回值类型
  • 实例化对象时编译器会自动的调用构造函数
  • 构造函数可以重载,也就是说我们可以创建多个构造函数。

 定义构造函数

 我们以上篇中的 栈的初始化来举例子,如果我们要用函数来实现栈的初始化的话,应该这样写:

void StackInit(Stack* ps)
{
    assert(ps);
    ps->array = (DataType*)malloc(sizeof(DataType) * 3);
    if (NULL == ps->array)
    {
        assert(0);
        return;
    }

    ps->capacity = 3;
    ps->size = 0;
}

如果我们用构造函数来实现话,就这样来实现:

class Stack
{
 public:
    Stack(int capacity = 4)
    {
            _array = (DataType*)malloc(sizeof(DataType) * 3);
            if (NULL == _array)
        {
            perror("malloc申请空间失败!!!");
            return;
        }
            _capacity = 3;
            _size = 0;
    }
};    

 我们就可以直接把在C++当中 实现的 初始化函数 copy 在这个构造函数中。

这个构造函数在创建 对象的时候就可以自动的去调用,也就是说,可以帮我们在创建对象的时候自动的去 初始化栈。这样我们在使用 这个栈的时候就不需要再去初始化一遍栈了。

 而且一般构造函数都是public的,如果是private 私有的就会报错:

当然我们上述说的是一般,也就是说不是必须的,构造函数也可以是 私有的,但是这是比较 高级的玩法。

如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦
用户显式定义编译器将不再生成。

 如果我们在类当中没有 定义 构造函数,那么编译器自动的的给我们创建一个 无参数的默认构造函数。

   在C++当中分为基本类型 / 内置类型,这些是语言本身定义的类型,如  int / double / char / 指针;自定义类型,如 用 class / struct 等等来创建的类型。

如果我们不写构造函数的定义,编译器会默认生成构造函数,内置类型不做处理,自定义类型会去调用他的默认构造:

class A
{
public:

	void Print()
	{
		cout << _a << " >>" << _b << " >> " << _c << endl;
	}

protected:
	int _a;
	int _b;
	int _c;
};

int main()
{
	A a;
	a.Print();

	return 0;
}

 输出:
C++ 类和对象(中)构造函数 和 析构函数

 我们发现没有初始化为0,这是在C++当中的语法规定的,但是现在有些新的编译器就会把这个成员默认值初始化为 0。 像VS2019 在类当中 如果在类当中定义了自定义类型的成员,那么其中的内置类型和自定义类型都会进行处理。但是 在 VS2013  就会处理。

 也就是说,内置类型处不处理是编译器个性化的行为,但是在C++当中是规定 内置类型是不进行处理的,我们要默认认为他是不处理的。

 所以,让编译器自己生成构造函数这种操作我们是不建议的,因为指不定这个编译器既不会对 内置类型进行 初始化0,所以,如果类当中有内置成员,我们就要自己实现构造函数来初始化 类当中的 内置成员。

 如果全部都是自定义类型的成员,可以考虑让编译器自己生成。

C++ 类和对象(中)构造函数 和 析构函数

 类当中的成员的缺省值

 注意:在C++11 当中,C++的开发团队也觉得,内置成员不处理,自定义成员处理,这样当时不妥当,所以大了一个补丁,不是把之前的语法改了,让函数在声明的时候可以给缺省值。

class A
{
public:

	void Print()
	{
		cout << _a << " >>" << _b << " >> " << _c << endl;
	}

protected:
	int _a = 1;
	int _b = 1;
	int _c = 1;
};

int main()
{
	A a;
	a.Print();

	return 0;
}

 输出:

C++ 类和对象(中)构造函数 和 析构函数

我们发现上述就输出的是我们 缺省值。注意:此处不是初始化,是在声明的时候给的 缺省值。

 这里的 成员的 缺省值 是给编译器默认的 构造函数用的。

 因为是编译器默认使用 构造函数生成的缺省值,所以当我们在 类当中实现了 构造函数,这个缺省值就没有用了:

class A
{
public:

	A(int a, int b, int c)
	{
		_a = a;
		_b = b;
		_c = c;
	}

	void Print()
	{
		cout << _a << " >>" << _b << " >> " << _c << endl;
	}

protected:
	int _a = 1;
	int _b = 1;
	int _c = 1;
};

int main()
{
	A a(9,9,9);
	a.Print();

	return 0;
}

 输出:

C++ 类和对象(中)构造函数 和 析构函数

 此时我们Print()函数就输出的是, 9  >>  9  >>  9 ,不是 1  >>  1  >>  1  了。

 构造函数重载需要注意的点

class A
{
public:

	A()
	{
		_a = 2;
		_b = 2;
		_c = 2;
	}

	A(int a, int b, int c)
	{
		_a = a;
		_b = b;
		_c = c;
	}

	void Print()
	{
		cout << _a << " >>" << _b << " >> " << _c << endl;
	}

protected:
	int _a = 1;
	int _b = 1;
	int _c = 1;
};

 如上述的两个构造函数就构成了函数重载,构造函数的形参,同样是可以有缺省参数的:

	A(int a = 0, int b = 0, int c = 0)
	{
		_a = a;
		_b = b;
		_c = c;
	}

 但是,构造函数中使用缺省参数会出现一些问题,如这个例子:

	A()
	{
		_a = 2;
		_b = 2;
		_c = 2;
	}

	A(int a = 0, int b = 0, int c = 0)
	{
		_a = a;
		_b = b;
		_c = c;
	}

 比如这例子,在语法上是支持的,也就是说,上述两个构造函数是支持语法的,但是在调用无参数的构造函数的时候会出现一些问题:

C++ 类和对象(中)构造函数 和 析构函数

 我们发现此时编译器就对该调用哪一个构造函数产生了歧义。

 当然我也不能  " A a1(); " 这样写,这样写与函数声明冲突,我们在下面会讲解。

 当然,我们给一个,或者两个参数都是可以的 ,因为他不会和 无参数的构造函数冲突。

所以,我们总结一下, 其实无参数构造函数和  全缺省 构造函数都属于是 默认构造函数,再加上 我们不写编译器就会生成的 默认构造函数,这三者只能有一个,因为这三者在外部的调用都是一样的编译器不能识别。

 构造函数的调用  

 构造函数的调用跟普通函数也不太一样,普通函数代用是函数名 + 参数列表构造函数调用是对象名 + 参数列表。

 像上述的例子:


int main()
{
	A a2(9,9,9);
	a2.Print();

	return 0;
}

 在类当中定义的 构造函数 是 以 类名为函数名来创建的,但是调用的时候,使用的是 创建的对象的名字。

 当这个构造函数没有参数的时候,如下:

	A()
	{
		_a = 2;
		_b = 2;
		_c = 2;
	}

 那么,就直接创建这个对象,不需要加 () 参数列表,都会自己调用 类当中  不带参数的 构造函数,如果这个例子:
 

class A
{
public:

	A()
	{
		_a = 2;
		_b = 2;
		_c = 2;
	}

	A(int a, int b, int c)
	{
		_a = a;
		_b = b;
		_c = c;
	}

	void Print()
	{
		cout << _a << " >>" << _b << " >> " << _c << endl;
	}

protected:
	int _a = 1;
	int _b = 1;
	int _c = 1;
};

int main()
{
	A a1;
	a1.Print();

	return 0;
}

 输出:

C++ 类和对象(中)构造函数 和 析构函数

 我们发现此时输出的是,无参数 构造函数 当中初始化的值。

 注意:有参数是需要加 "()" 在 "()" 当中传参,而如果我们想调用 无参数的构造函数,那么我们是不能 加  "()"  的,如果加  "()" 就会报错:

C++ 类和对象(中)构造函数 和 析构函数

 这是因为,如果这样写,会跟函数声明冲突,编译器不好识别。

 如上述的   " A a1(); "  是不是和 不带参数的 函数的 声明是一样,这样编译器就不好识别;但是如果是 带参数的 ,如:  " A a2(9,9,9); "  这样的就不会报错了,因为这样编译器就可识别了,因为我们在声明有参数函数的时候,参数是要加 参数的类型的: " void func ( int a, int b , int c);  " 这样的。而我们在调用有参数的构造函数的时候,是函数的传参,不需要 写 参数的类型。

我们还可以这样来给 对象当中的成员初始化:
 

typedef struct TreeNode
{
	struct TreeNode* left;
	struct TreeNode* right;
	int val;
}TreeNode;

class Tree
{
public:
	Tree(int val)
	{
		_root->left = nullptr;
		_root->right = nullptr;
		_root->val = val;
	}

protected:
	TreeNode* _root = nullptr;
};

int main()
{
	Tree Tr(1);

	return 0;
}

 如上,我们就创建了一个二叉树树结点,这个树结点的左右孩子指针都指向空,并且我们在主函数中创建这个对象的时候,可以个这个树结点当中的val 赋值。

 析构函数

 析构函数和构造函数的作用相反,它并不是完全的对  对象 进行销毁,局部对象进行销毁是由编译器来执行。所谓析构函数是对象在销毁的时候,才会执行的操作,来完成对象当中 一些成员的销毁工作。

特性

  •  析构函数的名字和类名相同,只是在最前面加上 "  ~  "   这个符号
  • 没有参数和返回值
  • 一个类只能有一个析构函数,若没有对析构函数进行定义,那么编译器会自动进行创建。注意:析构函数不能进行重载。
  • 在对象的生命周期结束的时候,编译器会自动调用析构函数。

析构函数的定义

如上篇当中的 栈的销毁:

class Stack
{
    ~Stack()
    {
        if (_array)
        {
            free(_array);
            _array = NULL;
            _capacity = 0;
            _size = 0;
        }
    }
}

如上述的~Stack() 函数就是 析构函数,他在 栈的对象销毁的时候就会自动调用。

也就是说,在上篇中提到的,内存泄漏问题,在程序运行的最后,只需要销毁 这个对象就会自动的销毁创建的栈空间。

 有了析构函数和构造函数的时候就不在怕初始化和清理函数了,也简化了。

我们上述也提到了,析构函数不写编译器也会生成默认的 析构函数,那么这个 默认的析构函数和构造函数是一样的,也是内置成员不处理,自定义成员就要按照自定义类型进行处理。

 在比如上述栈的例子,如果类当中都是 自定义类型,那么我们也可以不写析构函数,编译器自动生成的 析构函数就会帮我们 清理销毁 对象空间。

 C++ 类和对象(中)构造函数 和 析构函数

 拷贝构造函数

 当我们像通过某个对象当中的成员的值,在实现某些功能,但是实现过程有需要修改对象成员里的值,我们又不想修改这个对象当中成员的值,我们就可以创建一个 拷贝构造函数来帮助我们拷贝这个对象当中成员的值。

定义:

 拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存
在的类类型对象创建新对象时由编译器自动调用。

 例子:

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

protected:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date date();  //  创建日期对象
}

如上述例子,我们想把date 这个对象进行拷贝,我们可以在 Data 类当中实现一个 拷贝构造函数;

	Date(const Date& date)
	{
		_year = date._year;
		_month = date._month;
		_day = date._day;
	}

上述就是拷贝构造函数,我们可以发现,这个其实就是构造函数的一种重载,只是这个函数只有一个形参,而且这个形参是 我们需要拷贝 的 对象的 引用,一般我们在这个函数中,不想去修改外部的我们 拷贝的对象,所以这个引用是 const 不允许 修改的。在构造函数中对成员的值的修改也容易搞混,容易写反,写入const 也能防止这样的事情发生。

 注意:一下代码是编译报错的;

C++ 类和对象(中)构造函数 和 析构函数

 我们发现,我们在构造函数的创建的时候,他不给我们创建 本类 类型的参数的构造函数的重载函数,我们只能在此传入 本类 类型的 引用:
C++ 类和对象(中)构造函数 和 析构函数

 这是因为,在C++当中规定:在函数传参的时候,如果是内置类型就是直接拷贝;如果是自定义类型就必须先调用 拷贝构造函数 之后去完成拷贝。

 如下图:

C++ 类和对象(中)构造函数 和 析构函数

 这个例子,当调用 func(1) 时候就是直接拷贝,当调用 func(d1) 这个函数的时候,我们来调试来看看过程:

C++ 类和对象(中)构造函数 和 析构函数

 此时程序运行到 func(d1) 函数这一行,当我们 按下 F11 (或者是 fn + f11  看电脑) 单步执行程序,执行下一步时,我们发现,不是直接跳到 func(Date d1) 函数这一行,而是直接跳到 Date(const Date date) 拷贝构造函数这一行了:
C++ 类和对象(中)构造函数 和 析构函数

 这也就印证了,在函数传入 自定义类型的时候,先是传参,自定义类型传参就要先 调用拷贝构造函数。

 当我们在按下 f11 才进入到 func(Date date)这个函数。

那么,如果自定义类型传参是按照上述过程来实施的,那么如果我们在构造函数中,直接像下图一样写,那么就会出现无限函数递归的可怕结果:

C++ 类和对象(中)构造函数 和 析构函数

 其过程也不难理解,如下图所示:

 C++ 类和对象(中)构造函数 和 析构函数

 那么,如果我们在传参的时候,传的不是自定义类型,传入的自定义类型的引用,他是对象的一个别名,在传参的时候都不会开空间,那么他就不会调用拷贝构造函数。

 若未显式定义,编译器会生成默认的拷贝构造函数

 如果我们在类当中没有写 拷贝构造函数,那么编译器会自动给我们生成 拷贝构造函数。

此处默认的 拷贝构造函数 ,对于其中不同类型成员的拷贝是这样的:

  • 对于内置类型成员进行值拷贝/浅拷贝。
  • 对于自定义类型则会调用它的构造拷贝函数。

 所以实际上,对于简单的对象的拷贝,默认的拷贝构造函数是可以自动来完成的,如下例子:

C++ 类和对象(中)构造函数 和 析构函数

但是对于像栈,队列等等这些 对象当中动态开辟空间了的对象,那么默认的就不能拷贝成功了。 

 比如我们拷贝栈,栈当中存储了,动态开辟空间的空间的指针,top栈当中存储的有效数据的位置。那么如果我们使用默认 拷贝构造函数,只能拷贝上述两个 变量,不能开辟空间,那么函数当中拷贝的对象,和外部主函数中的对象,两个对象将使用同一块空间:

C++ 类和对象(中)构造函数 和 析构函数

 这样就违背了我们使用 拷贝构造函数的初衷。

而且,假设我们不在使用这两个对象的时候,就会调用对象的析构函数,来销毁栈空间,那么当其中一个对象调用析构函数销毁了空间之后,另一个对象再次销毁就会有问题。在两个操作之间没有对这个空间进行重新的声明,同一块空间不能销毁两次。

 C++ 类和对象(中)构造函数 和 析构函数

 比如这个例子,后定义的会先析构,那么st1 这个对象在析构的时候就有问题了。

 而且,这只是其中之一个问题,我们以后再 push  pop 等等操作都会有问题,两个对象使用的是一块空间,任何操作修改了其中以对象当中空间,都会影响另一个对象。

所以我们就要自己创建 拷贝构造函数,来拷贝其中的 栈空间,如下例子,我们采用深拷贝:

class Stack
{
public:
	Stack(int capacity = 4)
	{
		_array = (int*)malloc(sizeof(int) * 3);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		_capacity = 3;
		_top = 0;
	}

	Stack(const Stack& st)
	{
		_array = (int*)malloc(sizeof(int) * _capacity);
		if (_array == NULL)
		{
			perror("malloc fail");
			return;
		}

		memcpy(_array, st._array, sizeof(int) * _capacity);
		_top = st._top;
		_capacity = st._capacity;
	}
	
protected:
	int* _array = nullptr;
	int _capacity = 0;
	int _top = 0;

};

 如上就是是 Stack的构造函数  和 拷贝构造函数的创建方式,上述采用的是深拷贝。

 至此,我们就明白,为什么祖师爷在自定义类型的传参的时候,为什么不直接值传递,不直接把值传进来了。

因为,就像我们上述说的,如果我们直接把 值 传入,那么会导致,两个对象使用的是一个栈空间。

 所以拷贝构造是为深拷贝而生的,值传递都是使用 C++ 当中 默认 生成的 拷贝构造函数就可以实现了。

那么在函数的传参和 返回的时候,如果返回的是自定义类型,那么再传参的时候会 先去调用 这个自定义类型的 拷贝构造函数;在 函数返回的时候,会创建一个临时变量来暂时存储 这个返回值,这个临时变量的大小也是根据 自定义类型大小来的定的;如果这个自定义类型当中 的数据量很大,比如栈空间中存储了 10000 个数据,那么上述两种情况,我们都要先 拷贝 ,那么这个拷贝是消耗空间和时间的,我们程序的效率会下降。

像上述的两种情况,在数据量很大的情况是下是非常明显的。

所以一般情况下,我们能使用引用来进行 传参和 返回 尽量使用引用来 传参和返回。

 但是我们在使用引用传参和引用返回的时候,需要注意是,我们要用空间是否还存在有没有被销毁:

Stack& func()
{
	static Stack st;
	return st;
}

比如这种情况是可以返回的,因为 创建的 st 是静态的,函数执行完,函数栈帧销毁,他不会销毁。

Stack& func()
{
	 Stack st;
	return st;
}

像这个例子,st 就不会静态的,也不是全局的,是函数中的局部变量,那么函数执行完之后,他就会销毁,那么此时我们在返回这个已经销毁了的空间的引用,就会很危险:

Stack& func()
{
	 Stack st;
	return st;
}

int main()
{
	printf("-------\n");
	Stack st = func();
	printf("-------\n");

	return 0;
}

比如这个例子,在 main 函数中,我们使用 st  来接收,此时的st 就作为是 func ()函数中 st 的引用(别名) ,那么func()函数中的st 在函数销毁的时候就已经销毁了,那么我们在main函数中创建的 st 栈也要进行销毁,销毁之后,自动创建的析构函数会这个指针给置空,那么我们在main函数中的 st  也要进行释放,销毁,对空指针的销毁就会出现问题。

const成员

 C++ 类和对象(中)构造函数 和 析构函数

 如这个例子,第一个可以调用,但是第二个就不能调用了。

如下图所示:

C++ 类和对象(中)构造函数 和 析构函数

 第二中种中的传入的指针是const 的,但是在 Print()函数中是 Date* 的,这是权限的放大,当然就不能使用。而第一种是权限的平移,就可以使用。

那么像上述的 const Date d2() 这种如何调用其中的成员函数呢?

那么我们就考虑把 Print() 当中的 this 指针 变成 const 的,这样第一种情况就是权限的缩小,而第二种是权限的平移,我们就可以调用了。

但是 this 是 隐含的,我们不能显示的去写,所以祖师爷想了一个位置,就是在 成员函数定义的时候,在()后加一个 const 代表 this 指针是 const 的。这个const 修饰的是 *this。既然修饰的是*this,那么就代表这个 this 指针指向的内容不能被修改。

 C++ 类和对象(中)构造函数 和 析构函数

当我们在成员函数后面加上 const 修饰 this 指针之后,在外的无论是 普通的对象还是 const 修饰的对象都可以调用。

 问题:我们发现上述 在成员函数 之后 加上 const 修饰很香,那么是不是 所有的成员函数都 加 const 修饰呢?

 答案是否定的,我们上述 Print() 成员函数只是打印 对象当中的成员的值,没有对 对象当中的成员进行修改,但是如果这个成员函数是 需要修改 成员属性的,那么这个函数就不能 在函数后面加 const修饰。

 比如上述实现的 += 重载函数,上述的 _day  是Date类当中的成员,而上述的 _day += day ;这个代码会被编译器 转化为  this->_day += day;  但是 *this 是被 const 修饰的,意思就是说,this指针指向的内容不能被修改,所以我们发现,当我们加了 const 之后,上述代码编译报错了。

其实这里就是解决 权限的放大缩小平移的问题,如下例子:

C++ 类和对象(中)构造函数 和 析构函数

 这个在Date类当中重载的成员函数:

Date d1(2019,2,2);
const Date d2(2019,3,3);

d1 < d2;  // 1
d2 < d1;  // 2

 上述代码 1 能编译通过,但是 代码2 不能编译通过。代码2 的 d2 在传参的时候其实就是权限的放大,所以不会编译通过。

而当我们 把这个 < 重载函数 后加一个 const ;代码2 就可以编译通过了。

而,向上述的,其中没有修改 成员 属性的成员函数,我们都建议加上 const 修饰,如果成员函数中修改了 对象当中的成员属性,那么就不能加 const 修饰。

 理解const修饰词

	const int a = 10;
	int b = a; // 正确

	int& c = a; //错误

C++ 类和对象(中)构造函数 和 析构函数

 第一种不涉及权限的放大和缩小,因为这里只是一个拷贝,只是把 a 的值拷贝给 b,在拷贝之后,b 的改变不影响 a ;而第二种c 是a 的别名,c  的改变会改变 a  ,这里就设计权限的放大。

C++ 类和对象(中)构造函数 和 析构函数

 要想引用 c 也是不能改变的,此时是权限的平移。

那么指针也是和 引用类似的,如果按照上述的错误操作,也是权限的放大,会报错:

C++ 类和对象(中)构造函数 和 析构函数

  •  1. const对象可以调用非const成员函数吗?
  • 2. 非const对象可以调用const成员函数吗?
  • 3. const成员函数内可以调用其它的非const成员函数吗?
  • 4. 非const成员函数内可以调用其它的const成员函数吗?

 容易出错的地方:

C++ 类和对象(中)构造函数 和 析构函数

 如上所示,npos是在类当中声明的全局变量,类当中只是声明,npos的定义在全局当中。此时我们是不能给 npos赋上缺省值的,因为类当中成员变量的缺省值是给 初始化列表看的,而对于npos全局变量,他的定义不在初始化列表,而是在全局当中定义,如下所示(编译报错):

C++ 类和对象(中)构造函数 和 析构函数

 但是如果把这个npos变量用const进行修饰,就可以在类当中定义缺省值了,而且不用再全局当中进行定义

C++ 类和对象(中)构造函数 和 析构函数

 此处的语法比较怪,并不是说类似上述的所以const修饰的全局变量都可以像上述一样定义缺省值,而是只有size_t类型才可以,如下所示,我们换成 double 类型就不行了

        C++ 类和对象(中)构造函数 和 析构函数

 所以,我们建议 size_t 类型的全局变量(static)不想上述一样使用,还是统一和其他类型一样声明和定义分离

 

 取地址及const取地址操作符重载

Date* operator&()  // 普通对象的取地址重载函数
{
    return this;
}
const Date* operator&()const  // const 对象的取地址重载函数
{
    return this;
}

其他的操作符,对于自定义类型该如何实现具体功能,编译器是无法判断的,但是取地址不同,他只需要返回这个对象的地址就行了。所以我, 使用编译器默认生成的 取地址 重载函数也可以实现取地址功能。

除非你不想要别人取到 这个 普通对象的地址,那么就直接返回 nullptr。文章来源地址https://www.toymoban.com/news/detail-430778.html

到了这里,关于C++ 类和对象(中)构造函数 和 析构函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】类和对象(中)之构造函数与析构函数

    👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.构造函数 1.1概念 1.2特性 2.析构函数 2.1概念 2.2特性 我们继续学习类和对象,今天主要讲解构造

    2024年02月07日
    浏览(36)
  • 【C++入门到精通】C++入门 —— 类和对象(构造函数、析构函数)

    目录 一、类的6个默认成员函数  二、构造函数 ⭕构造函数概念 ⭕构造函数的特点 ⭕常见构造函数的几种类型 三、析构函数      ⭕析构函数概念     ⭕析构函数的特点 ⭕常见析构函数的几种类型 四、温馨提示          这一篇文章是上一篇的续集(这里有上篇链接)

    2024年02月15日
    浏览(42)
  • 【C++】类和对象②(类的默认成员函数:构造函数 | 析构函数)

    🔥 个人主页: Forcible Bug Maker 🔥 专栏: C++ 目录 前言 类的6个默认成员函数 构造函数 概念 构造函数的特性及用法 析构函数 概念 析构函数的特性及用法 结语 本篇主要内容:类的6个默认成员函数中的 构造函数 和 析构函数 进入到类和对象内容的第二节,上篇博客中介绍了

    2024年04月16日
    浏览(41)
  • 【C++初阶】四、类和对象(构造函数、析构函数、拷贝构造函数、赋值运算符重载函数)

    ========================================================================= 相关代码gitee自取 : C语言学习日记: 加油努力 (gitee.com)  ========================================================================= 接上期 : 【C++初阶】三、类和对象 (面向过程、class类、类的访问限定符和封装、类的实例化、类对象模

    2024年02月05日
    浏览(45)
  • 【C++】:类和对象(中)之类的默认成员函数——构造函数and析构函数

    如果一个类中什么成员都没有,简称为空类 空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数 由于编译器的优化 我们未给_a赋值 这里是不会报

    2024年02月08日
    浏览(36)
  • 【C++】类与对象(构造函数、析构函数、拷贝构造函数、常引用)

       🌈个人主页: 秦jh__https://blog.csdn.net/qinjh_?spm=1010.2135.3001.5343 🔥 系列专栏:   目录 类的6个默认成员函数 构造函数 特性  析构函数 特性  析构的顺序 拷贝构造函数 特性 常引用      💬 hello! 各位铁子们大家好哇。              今日更新了类与对象的构造函数、

    2024年02月21日
    浏览(35)
  • C++初阶类与对象(二):详解构造函数和析构函数

    上次为类与对象开了一个头:C++初阶类与对象(一):学习类与对象、访问限定符、封装、this指针 今天就来更进一步 如果一个类中什么成员都没有,简称为空类。 空类中并不是什么都没有,任何类在什么都不写时,编译器会 自动生成上面6个默认成员函数 。 默认成员函数

    2024年01月19日
    浏览(37)
  • C++之构造函数、析构函数、拷贝构造函数终极指南:玩转对象的诞生、生命周期与复制

    W...Y的主页 代码片段分享  前言: 在上篇内容里,我们初识了C++中的类与对象,了解了类的定义、类的实例化、 类的作用域等等,今天我们将继续深入了解类与对象的相关内容,学习构造函数、析构函数与拷贝构造函数,话不多说我们发车!!! 目录 类的6个默认成员函数

    2024年02月06日
    浏览(34)
  • 【是C++,不是C艹】 类与对象 | 默认成员函数 | 构造函数 | 析构函数

    💞💞 欢迎来到 Claffic 的博客 💞💞  👉  专栏: 《是C++,不是C艹》👈 前言: 在完成类与对象的认识后,我们接着学习类与对象的第二部分:默认成员函数,它包括构造函数,析构函数,拷贝构造,赋值重载,普通对象取地址和const对象取地址重载,放心,这一期不会都

    2024年02月09日
    浏览(31)
  • 【C++初阶】类与对象:6个默认成员函数-----构造函数和析构函数

        我们在写代码的时候经常会忘记初始化和销毁,C++的构造函数和析构函数就能避免这个问题。 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。 1.构造函数是一个特殊的成员函数; 2. 名字与类名相同 ,创建类类型对象时由 编译器自动调用

    2024年02月05日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包