类和对象(详解初始化列表, static成员变量, 友元,内部类)

初始化列表

之前我实现的构造函数时, 初始化成员变量主要使用函数体内赋值, 构造函数初始化还有另一种方式, 就是初始化列表.

初始化列表的使用方式是以一个冒号开始,接着是以逗号分隔的数据成员列表, 每个"成员变量" 后买你跟一个放在括号种的初始值或表达式.


这里需要注意的是,每个成员变量在初始化列表中只能出现一次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。

必须在初始化列表初始化的变量

为什么明明可以在函数体内初始化, 偏偏又多出来了一个初始化列表呢??这不是冗余吗??

其实是因为有,三种变量它们没有办法在函数体内初始化.

  • 引用成员变量,
  • const成员变量,
  • 没有默认构造的类类型变量,
    那么为什么呢??

对于引用变量, 我们知道定义它的是时候必须要初始化, const 成员变量定义的时候也要初始化并且初始化后的值不能被改变. 这的的必须初始化的意思就是在定义的时候给一个值.

而在类的里面定义变量时只是声明, 真正定义的时候是在初始化列表中进行定义.

在函数体内进行的操作是对变量进行赋值

正确写法:

那么对于没有默认构造的类类型的变量

在初始化列表中进行初始化时, 会对类类型变量初始化,这时候就会调用拷贝构造

如果没有默认构造就会编译报错

而如果在函数体内进行赋值,由于该对象未被初始化,程序将无法通过编译。


C++11支持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显示在初始化列表初始化的成员使用的。

也就是说当成员变量没有在初始化列表中显式初始化时,编译器会使用声明时提供的缺省值进行初始化。

注意这里不是初始化,这里给的是缺省值,这个缺省值是给初始化列表的如果初始化列表没有显示初始化,默认就会用这个缺省值初始化 .

这里要将它与构造函数的内的缺省值做区别, 构造函数的缺省值只有你使用它的时候才有作用, 而成员变量的缺省值无论是否调用构造函数都会起作用。

构造函数的缺省值仅在调用该构造函数且未提供实参时才会被使用,而成员变量的缺省值在任何构造函数调用时都会作为初始值(除非在初始化列表中被显式覆盖)。

所以尽量使用初始化列表初始化,因为那些你不在初始化列表初始化的成员也会走初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会用这个缺省值初始化。如果你没有给缺省值,对于没有显示在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有显示在初始化列表初始化的自定义类型成员会调用这个成员类型的默认构造函数,如果没有默认构造会编译错误。
初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的的先后顺序无关。建议声明顺序和初始化列表顺序保持一致。

看到这里让我来看一到非常经典的例题

cpp 复制代码
#include<iostream>
using namespace std;
class A
{
public:
    A(int a)
        :_a1(a)
        , _a2(_a1)
    {
    }
    void Print() {
        cout << _a1 << " " << _a2 << endl;
    }
private:
    int _a2 = 2;
    int _a1 = 2;
};
int main()
{
    A aa(1);
    aa.Print();
}

朋友们觉得它的运行情况是什么呢???

初始化列表总结:
无论是否显示写初始化列表,每个构造函数都有初始化列表;

**无论是否在初始化列表显示初始化成员变量,每个成员变量都要走初始化列表初始化

static静态成员

  • 用static修饰的成员变量, 称之为静态成员变量, 静态成员变量一直要在类外初始化.
  • 静态成员是被类的所有对象共享的成员,而不是每个对象各自拥有一份拷贝。静态成员可以是变量或函数,它们属于类本身而非类的对象。
  • 用static修饰的成员函数,称之为静态成员函数。静态成员函数没有this指针,只能访问静态成员变量或其他静态成员函数。不能访问非静态的, 因为没有this 指针

  • 静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表。

  • 非静态的成员函数,可以访问任意的静态成员变量和静态成员函数。

  • 突破类域就可以访问静态成员,可以通过类名:.静态成员或者对象.静态成员来访问静态成员变量和静态成员函数。

  • 静态成员也是类的成员,受public、protected、private访问限定符的限制。


友元

如果在类外面写了一个函数, 如果想访问类内部的成员变量, 有三种方法

  1. 成员放公有
  2. 友元函数
  3. 重载为成员函数
    现在我们来详细介绍一下友元
    友元提供了一种突破类访问限定符封装的方式,友元分为:友元函数和友元类,在函数声明或者类声明的前面加friend,并且把友元声明放到一个类的里面。

外部友元函数可访问类的私有和保护成员,友元函数仅仅是一种声明 ,他不是类的成员函数。

友元函数可以在类定义的任何地方声明不受类访问限定符限制。
一个函数可以是多个类的友元函数。

下面我们来看看友元类

  • 友元类中的成员函数都可以是另一个类的友元函数,都可以访问另一个类中的私有和保护成员。
  • 友元类的关系是单向的,不具有交换性,比如A类是B类的友元,但是B类不是A类的友元。 友元类关系不能传递,如果A是B的友元,B是C的友元,但是A不是C的友元。

内部类

如果一个类定义在另一个类的内部, 这个内部类就就叫做内部类.

  • 内部类是一个独立的类,跟定义在全局相比,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。
  • 内部类默认是外部类的友元类。

内部类本质也是一种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使用,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地方都用不了。

匿名对象

  • 用类型(实参)定义出来的对象叫做匿名对象,相比之前我们定义的类型对象名(实参)定义出来的叫有名对象
  • 匿名对象生命周期只在当前一行,一般临时定义一个对象当前用一下即可,就可以定义匿名对象。
相关推荐
磊 子1 小时前
多继承和多态性
开发语言·c++
AbandonForce1 小时前
C++11:列表初始化||右值和移动语义||引用折叠和完美转发||可变参数模板||lambda表达式||包装器(function bind)
开发语言·数据结构·c++·算法
khalil10201 小时前
代码随想录算法训练营Day-50 图论02 | 99.岛屿数量-深搜、99.岛屿数量-广搜 、100.岛屿的最大面积
数据结构·c++·算法·leetcode·深度优先·图论
Brilliantwxx1 小时前
【C++】模版进阶(特化+分离编译+非类型模版参数)
开发语言·数据结构·c++·算法
Black蜡笔小新1 小时前
自动化AI算法训练服务器DLTM企业级AI模型工作站构筑企业AI自主可控新模式
人工智能·算法·自动化
bnmoel1 小时前
数据结构深度剖析链表全集:结构实现、分类与底层原理全解析
c语言·数据结构·算法·链表·双向链表
Languorous.1 小时前
C++数据结构高阶|跳表(Skip List)深度解析:从原理到手写实现,面试高频考点全覆盖
数据结构·c++·list
许长安1 小时前
RingBuffer:面向网络编程的环形缓冲区实现
服务器·网络·c++·经验分享·笔记·缓存
Justice Young1 小时前
数据结构:邻接矩阵和邻接表的区别
数据结构