文章目录
- 类六个默认存在的成员函数
- 构造函数:
- 析构函数:
- 拷贝构造函数:
- 拷贝构造详解及细节:
- 赋值运算符重载;
- 取地址及const取地址操作符重载
- const修饰的含义:
类六个默认存在的成员函数
-
构造函数
-
析构函数
-
拷贝构造函数
-
赋值运算符重载
-
const成员函数
-
取地址及const取地址操作符重载
**一个类中,不管存不存在成员变量和成员函数,其内部都会默认生成以上六个成员函数 **
构造函数:
在一个类中,如果没有自定义任何构造函数,会自动生成一个默认的无参构造函数,其没有任何功能。如果自己定义过一次构造函数,则不会生成默认构造函数,如果我们定义的不是无参构造方法,以后就不可再使用无参构造了,当然我们可以在定义出来一个无参构造函数。构造函数的格式: 类名(参数列表){操作}…
构造函数还有个点,就是当一个类包含另一个类的时候,默认构造函数会默认调用被包含类的默认构造函数
析构函数:
析构函数的作用和构造函数是相反的,构造函数的作用是初始化类成员变量,析构函数的作用就是当对象使用完了以后,需要销毁的时候对内部的数据结构进行释放操作 格式: ~类名(){成员变量释放操作}
举个例子:数组栈的C++实现方法
//File:Stack.h
#include<iostream>
using namespace std;
class Stack {
private:int* arr;int capcity;int top;bool CheckMemory();
public:Stack();~Stack();Stack(const Stack& s);void PushBack(int n);int TopStack();void PopStack();bool isEmpty();
};//File:Stack.cpp
#include"Stack.h"
Stack::Stack() {capcity = 4;top = -1;int* temp = (int*)malloc(sizeof(int) * capcity);if (temp == nullptr) {perror("malloc fail");exit(-1);}arr = temp;
}
Stack::~Stack(){free(arr);capcity=top = 0;
}
Stack::Stack(const Stack& s) {this->capcity = s.capcity;this->top = s.top;//deepin copyint* temp = (int*)malloc(sizeof(int) * s.capcity);if (temp == nullptr) {perror("copy fail");exit(-1);}this->arr = temp;memcpy(arr, s.arr, sizeof(int) * capcity);
}
void Stack::PushBack(int n) {if (CheckMemory()) {//扩容int* temp=(int*)realloc(arr, sizeof(int) * capcity * 2);if (temp == nullptr) {perror("realloc fail");exit(-1);}arr = temp;capcity *= 2;}arr[++top] = n;
}
int Stack::TopStack() {return arr[top];
}
void Stack::PopStack() {top--;
}
bool Stack::CheckMemory() {return top == capcity - 1;//ture is full,false isn't full
}
bool Stack::isEmpty(){return top == -1;
}
拷贝构造函数:
拷贝构造就有意思了,在开始讲解之前我先用一段代码提问下大家:
class demo {
private:int _a;
public:demo() {_a = 1;cout << "demo()" << endl;}~demo(){cout << "~demo()" << endl;}demo(const demo& d) {_a = d._a;cout << "demo(const demo& d)" << endl;}
};
int main() {demo d1;demo d2=d1;return 0;
}
我想问下大家:这个main函数里的d2=d1 是进行的赋值操作还是进行的拷贝构造的操作?
答案:
显然这里进行的是拷贝复制,这里我们将讲解下这是怎么回事,以及为什么这里的拷贝构造函数为什么要传引用变量
拷贝构造详解及细节:
1. 首先由C++的规定,我们在对一个并未初始化的类进行值传递的时候,调用的就是拷贝构造函数,而不是赋值函数,这就很简单的解决了这里为什么调用的是拷贝构造函数的问题。
**2.第二个令人感到困惑的点就是,拷贝构造函数我们传递的是引用数据类型,首先也有个硬性规定,这里传递的必须是指针,另外这也是为了和第一点的特性做自洽处理,因为我们如果值传递话,会陷入一种无穷递归的情况,每次传值都会进行一次拷贝调用,每次拷贝调用,也会触发值传递。这里没有任何方法可以控制,因为这个递归他不会进入到函数每部,除非栈空间耗尽,不然他会一直递归 **
3. 拷贝构造在遇到成员变量也是一个类的时候,也会调用被包含类的默认构造函数进行拷贝操作
4. 深浅拷贝问题,其实我们大多数时候默认的拷贝构造,只会完成浅拷贝,这就会导致一个问题,两个类的指针成员函数都指向一块堆空间,这样在对象的生命周期结束时候,进行销毁操作在析构函数里会对一片地址重复释放,这样会直接引起程序的崩溃
赋值运算符重载;
其实赋值运算符重载的注意事项和拷贝构造函数的注意点最重要的就是深浅拷贝的问题,不同的情况要灵活运用,还有一个重要的就是赋值操作运算符重载只能在类的内部进行定义,不能定义为全局函数,其实这也很好理解,因为如果我们不在类内定义的话,编译器会自动生成一个默认的赋值函数,这样会与全局的赋值运算符重载冲突。
取地址及const取地址操作符重载
其余两个默认成员函数其实并不怎么重要了,这里我也就不做过多的赘述,下边我需要讲一些重要的概念
demo* operator&(){return this;
}const demo* operator&()const
{
return this ;
}
const修饰的含义:
eg:
const int& a=1;
int& b=1;
const int& c=a+2;
int& d=a+2;
请各位判断上边代码的对错情况:
答案:√×√×
这是为什么呢?
主要是因为上述代码的右值都是临时变量,而临时变量都具有常性,而引用临时变量稍有不慎就会造成权限的放大,大家自己想一下,定义出来的a是存在栈上的还是在常量区。