【C++】深度刨析构造函数-让你对析构函数有全新认识的一篇文章

目录

1.构造函数体赋值

2.初始化列表

3. explicit关键字

4.static关键字

1.在c语言中:

2.在C++中:

5.友员函数:

6.友元类

7.内部类

1.概念:

2.特性:


1.构造函数体赋值

  • 在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值,

  • 虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称作为类对象成员的初始化,构造函数体中的语句只能将其称作为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。

2.初始化列表

  • 初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。以下形式:

  • 当然我们的拷贝构造函数也是构造函数,那么它也有初始化列表

  • 【注意】

  • 1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

  • 2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
  • 引用成员变量:
    • 因为引用变量创建时必须要初始化,所以我们将引用变量当作成员函数时,也要将引用初始化。
  • const成员变量:
    • 因为在C++中我们将const定义的变量作为常量来使用,所以要在定义时就要给它赋一个值。
  • 自定义类型成员(该类没有无参的默认构造函数)

  • 3.建议:
  • 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。如果用户没有显示给出,则编译器就hi自己补全---内置类型用随机值初始化,自定义类型调用默认的构造函数(这里一定区找无参的构造函数)。

  • 1.成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

3. explicit关键字

  • 生成临时变量进行赋值,这里我们构造一个场景,给类型中定义一个单参的构造函数

  • 我们将一个整型数赋给Date类型,我们此时发现也是可以的,我们将每一次构造和析构函数调用时都将其this指针的地址打印出来:可以看到我们在进行int类型给Date赋值时因为类中有单参的构造函数,所以会先生成一个临时变量,然后再用这个临时变量给日期类

  • 虽然可以这样隐式类型转化,但是这样的代码可读性并不高,所以我们可以用 explicit关键字修饰函数禁止这种情况

  • 使用了explicit这里编译就会显示报错

  • 对于全缺省参数我们也要用explicit修饰

4.static关键字

  • 1.在c语言中:

  • 局部变量:
    • 普通局部变量是指在任何一个函数内部定义的变量(不加static修饰符)都属于这个范畴。编译器一般不对普通局部变量进行初始化,也就是说它的值在初始时是不确定的,除非对其显式赋值。普通局部变量存储于进程栈空间,使用完毕会立即释放。静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。变量在全局数据区分配内存空间;编译器自动对其初始化,其作用域为局部作用域,当定义它的函数结束时,其作用域随之结束
  • 全局变量:
    • 全局变量定义在函数体外部,在全局数据区分配存储空间,且编译器会自动对其初始化。普通全局变量对整个工程可见,其他文件可以使用extern外部声明后直接使用。也就是说其他文件不能再定义一个与其相同名字的变量了(否则编译器会认为它们是同一个变量)。静态全局变量仅对当前文件可见,其他文件不可访问,其他文件可以定义与其同名的变量,两者互不影响。在定义不需要与其他文件共享的全局变量时,加上static关键字能够有效地降低程序模块之间的耦合,避免不同文件同名变量的冲突,且不会误使用。
  • 函数:
    • 函数的使用方式与全局变量类似,函数在当前文件中定义,在其他文件中声明就可以使用了,在函数的返回类型前加上static,就是静态函数。其特性如下:静态函数只能在定义它的文件中可见,其他文件不能引用该函数。不同的文件可以使用相同名字的静态函数,互不影响。
  • 2.在C++中:

  • 修饰类中成员变量:
    • 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态的成员变量一定要在类外进行初始化

    • 静态成员变量放在类中,但是不影响类的大小,不占空间,静态成员变量是类的特性是每个对象共享的,不是存放在对象中的,所以不可以放在初始化列表当中初始化。
    • 静态成员变量的访问:[类名]::[静态成员变量的名字](Date::_count)(推荐这种访问,因为对象.静态成员变量也是转化为这样访问)||[对象].[静态成员变量名字](d1._count)
    • 【特性 】
    • 1. 静态成员为所有类对象所共享,不属于某个具体的实例
    • 2. 静态成员变量必须在类外定义,定义时不添加static关键字
    • 3. 类静态成员即可用类名::静态成员或者对象.静态成员来访问
    • 4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
    • 5. 静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值,如果将静态成员变量放在private中也就不可以在类外进行访问
  • 修饰类中成员函数:
    • 静态成员函数没有隐藏的this指针,静态成员函数可以在类外通过Date::[函数名](推荐这种访问,因为[对象].[静态成员函数]也是转化为这样访问)访问,也可以用[变量名字].[成员函数]访问。

    • 【问题】
    • 1. 静态成员函数可以调用非静态成员函数吗?
    • 答案:不可以,因为静态成员函数没有this指针
    • 2. 非静态成员函数可以调用类的静态成员函数吗?
    • 答案:可以,因为静态成员函数属于类作用域中,所以类中的函数都可以调用静态成员函数。
    • 3.静态成员函数可以被const修饰吗?
    • 答案:不可以,因为const指针修饰的是this指针的指向

5.友员函数:

  • 当我们想打印一个类对象成员中的成员变量时,我们可以在类中写一个打印函数将变量内容全部输出,也可以将"<<"运算符重载,直接打印成员变量。
  • 我们在类中直接重载运算符"<<"

  • 但是我们将一般都是将输出内容插入到输出流对象中,所以我们就要想办法将重载的函数的第一个参数设置为输出流对象。我们就要将重载函数放到全局作用域中定义,但是在全局作用域中无法对类对象中成员变量进行访问,所以我们要在类中对重载函数声明,声明为友员函数。返回值类型也得是输出流对象的引用,这样就可以支持连续输出。

  • 其实cout也是一个对象是输出流对象,它将我们的所有内置对象都重载了

  • 【注意】:
  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰,因为const是修饰的this指针,友元函数不是类的成员函数,所以不能用const修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用和原理相同

6.友元类

  • 友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
  • 友元关系是单向的,不具有交换性。
  • 比如下面的Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。

  • 友元关系不能传递
  • 如果B是A的友元,C是B的友元,则不能说明C时A的友元

7.内部类

  • 1.概念:

  •         如果一个类定义在另一个类的内部,这个内部类就叫做内部类。注意此时这个内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去调用内部类。外部类对内部类没有任何优越的访问权限。注意:内部类就是外部类的友元类。注意友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
  • 2.特性:

  • 1. 内部类可以定义在外部类的public、protected、private都是可以的。
  • 2. 注意内部类可以直接访问外部类中的static、枚举成员,不需要外部类的对象/类名。
  • 3. sizeof(外部类)=外部类,和内部类没有任何关系。(也就是外部类在计算空间大小的收是不将内部类的大小计算进去的)

看到这里如果觉得有用不如点个赞再走吧!!!

 

猜你喜欢

转载自blog.csdn.net/weixin_45897952/article/details/123785370
今日推荐