C++类和对象下(初始化列表,静态成员,explicit关键字,友元)(下)

简介: C++类和对象下(初始化列表,静态成员,explicit关键字,友元)

3.匿名对象

是,我func现在是改不了了,但是你main函数也访问不了啊

怎么办呢?

1.封装get函数

不错,而且我func函数也无法修改你这个count了

但是你这样的前提是你这个main函数里面有一个A的对象啊

这样你才能用对象.去访问这个get函数啊

可是如果我原本就没有在这个main函数里面创建一个A类型的对象

那你就只能这样了

可是你说我为了能够得到这个类到底实例化出了多少个对象,还要去特意在我main函数里面特意实例化出一个对象,

太挫了吧

而且我还要考虑取名字的事情,而且我创建这个对象只需要让它完成者一个任务即可,我后续也不想用它,能不能让它在执行完这个任务之后就销毁呢?

这就可以用到匿名对象了

匿名对象就是A()

它的特点是:

1.不用取名字

2.它的生命周期只有

cout << wzs::A().GetCount()-1 << endl;

这一行

完美符合了我刚才的需求

请注意:但是这个-1有点碍眼,让我这个代码不是很帅

显得我这个人的水平很挫

怎么办呢?

可是想要访问这个get函数就是必须创建一个对象

然后用对象.才能访问啊

能不能不用对象呢?

于是static成员函数出现了

4.static成员函数

这样就能把-1这个影响我代码美观性地东西就消失了

到了这里我们这个需求就完美解决了

5.总结

到了这里,大家就能对下面这张图片有更深刻的理解了

6.OJ 计算1+2+…+n

下面我们来做一道OJ题来巩固一下上面的知识

求1+2+3+…+n

这么多限制条件,怎么办呢?

其实这个题的本意就是让我们利用类的静态成员来解决这个问题

注意:牛客网的编程题所采用的编译器是支持变长数组的,VS编译器是不支持变长数组的

但是这个代码还不是特别好,当我们介绍完内部类之后,我们还会对这个代码进行进一步修改

三.explicit关键字

1.一个奇怪的现象

wzs::B b2 = 1;
竟然能这么创建一个对象,这是怎么做到的呢?
• 1
• 2

其实:

我们之前在C++入门-引用中介绍过:

因此我们可以认为是这样进行的

那么下面的问题就是

为什么1这个内置类型能隐式类型转换为我B这个类类型呢?

其实这里有一个规则:

当某个类的构造函数可以只传入一个参数时,而且这个参数的类型跟我这个内置类型相同的时候
就可以发生这个类类型对象和这个内置类型变量之间的隐式类型转换
下面这个例子能帮大家更好地去理解
class A
{
public:
    构造函数第1种情况:
    A(int val) //单参数构造函数
    :_var1(val)
    {}         
    A(int val1,int val2 = 2,int val3 = 3)//半缺省,且只传一个参数即可完成对象的构造
    :_var1(val1)
    ,_var2(val2)
    ,_var3(val3)
    {}
    A(int val1 = 1,int val2 = 2,int val3 = 3)//全缺省,这个构造函数允许只传一个参数进行构造
    :_var1(val1)
    ,_var2(val2)
    ,_var3(val3)
    {}
  private:
      int _var1;
      int _var2;
      int _var3;
};
它们都允许: A a = 1;
但是当这个内置类型跟我这个参数的类型不匹配时:
例如   A a = nullptr; 这样就无法发生隐式类型转换

而且还有一种书写方式:列表初始化

zs::A a={2023,11,3};
• 1

这个本质也跟上面那个内置类型1隐式转换为A类类型的对象一样:

可是有一个问题啊

你跟我讲这么一大堆,有什么用呢?

2.用途

我们这里先用一下STL中的vector容器

当我们在leetcode做OJ题的时候:

#include <vector>
int main()
{
  vector<zs::A> v;
  //当我们在leetcode做OJ题时:
  //1.在没有学习这个知识之前我们平常的做法
  zs::A a(1);
  v.push_back(a);
  //2.学习了匿名对象后 
  v.push_back(zs::A(1));//  这代码写起来爽了很多
  //3.学习了内置类型和自定义类型之间的隐式转换后
  v.push_back(1);//     这代码写起来太爽了,可是只有在构造函数允许只传一个参数的时候才可以啊
  //4.学习了列表初始化隐式类型转换为类类型对象后
  v.push_back({ 2023,11,3 });//   爽飞了  ,而且允许只传一个参数对我无效
  return 0;
}

可见这个知识是很棒的

3.为什么要有explicit呢?

那么你介绍的这个explicit是什么呢?

他有什么用呢?

四.友元

1.友元函数

我们之前在介绍运算符重载的时候提到过友元函数

当时是为了解决日期类的流插入和流提取运算符不能定义在类内,但是还想要访问这个类的成员变量的矛盾

详细的请况大家可以去看这篇博客:

C++类和对象中:运算符重载+const成员函数+日期类的完善

2.友元类

1.语法:

这里以C类是B类的友元为例
class B
{
  friend class C;//友元声明不受类访问限定符的限制
}
class C
{
   B b;//需要有一个B类的对象
   //然后想要访问B类的成员变量或者成员函数的时候就可以用这个B类的对象.去访问
}

2.实例:

namespace zs
{
class B
{
public:
  friend class C;
private:
  void FuncOfB()
  {
    cout << "private:  FuncOfB()调用" << endl;
  }
  int _bint = 1;
  static int _StaticInt;
};
int B::_StaticInt = 5;
class C
{
  public:
    void SetMemberOfB(int val)
    {
      b._bint = val;
      B::_StaticInt = val;
    }
    void ReadMemberOfB()
    {
      cout << b._bint << endl;
      cout << B::_StaticInt << endl;//只能这样访问
    }
    void ReadFuncOfB()
    {
      b.FuncOfB();
    }
  private:
    int _cint;
    B b;
  };
}
int main()
{
  zs::C c;
  c.SetMemberOfB(100);
  c.ReadMemberOfB();
  c.ReadFuncOfB();
  return 0;
}

3.总结

关于友元类的访问方法其实大家只需要记住一点:

友元类:我是你的朋友,

我也只是能够访问你的私有成员而已

访问方法跟普通类访问你的公有成员的方法一样

注意:友元关系是单向的,不具有交换性

因此上面的类B就无法访问类C的私有成员

3.内部类

1.语法

2.实例

namespace zs
{
  //注意:D是外部类,E是内部类.E天生就是D的友元,但是默认情况下D是不能访问E的,除非在E中声明D是E的友元类
  class D
  {
  public:
    class E
    {
    public:
      void GetStaticMemberOfD()
      {
        cout << _StaticInt << endl;
        //yes  这是上述第3条特性:  内部类可以直接访问外部类的static成员,不需要外部类的对象/类名
        //cout << _NonStaticInt << endl;//err  内部类不能直接访问外部类的非static成员
        cout << d._NonStaticInt << endl;//yes  只能用对象.去访问
        //也就是说内部类访问外部类:只不过是静态成员可以直接访问而已,非静态成员的访问跟普通类访问外部类的非静态成员的方法一样
      }
    private:
      zs::D d;
    };
  private:
    static int _StaticInt;
    int _NonStaticInt = 10;
  };
  int D::_StaticInt = 1;
}

3.总结:

其实C++不常用内部类

OJ题的优化

学习了内部类之后,我们就能对那道OJ题进行优化

以上就是类和对象下的全部内容,希望能对大家有所帮助!!!


相关文章
|
16天前
|
存储 编译器 C语言
C++入门: 类和对象笔记总结(上)
C++入门: 类和对象笔记总结(上)
30 0
|
22天前
|
存储 安全 算法
【C/C++ 关键字 函数说明符 】C++ noexcept 关键字(指定某个函数不抛出异常)
【C/C++ 关键字 函数说明符 】C++ noexcept 关键字(指定某个函数不抛出异常)
24 0
|
24天前
|
安全 编译器 程序员
【C++ 泛型编程 进阶篇】 C++ 泛型编程 模板与异常处理、模板与友元之间的使用(一)
【C++ 泛型编程 进阶篇】 C++ 泛型编程 模板与异常处理、模板与友元之间的使用
29 1
|
22天前
|
设计模式 算法 安全
【C/C++ 关键字 函数说明符 】C++ final关键字(修饰成员函数无法被子类重写覆盖)
【C/C++ 关键字 函数说明符 】C++ final关键字(修饰成员函数无法被子类重写覆盖)
36 1
|
22天前
|
算法 安全 编译器
【C++ 关键字 override】C++ 重写关键字override(强制编译器检查该函数是否覆盖已存在的虚函数)
【C++ 关键字 override】C++ 重写关键字override(强制编译器检查该函数是否覆盖已存在的虚函数)
23 0
|
22天前
|
算法 Java 编译器
【C++ 关键字 virtual 】C++ virtual 关键字(将成员函数声明为虚函数实现多态
【C++ 关键字 virtual 】C++ virtual 关键字(将成员函数声明为虚函数实现多态
24 0
|
7天前
|
编译器 C语言 C++
【C++的奇迹之旅(二)】C++关键字&&命名空间使用的三种方式&&C++输入&输出&&命名空间std的使用惯例
【C++的奇迹之旅(二)】C++关键字&&命名空间使用的三种方式&&C++输入&输出&&命名空间std的使用惯例
|
20天前
|
存储 算法 编译器
【C++ 关键字 static_assert 相关问题】C++ 关于静态断言的编译问题 ,深入了解静态断言
【C++ 关键字 static_assert 相关问题】C++ 关于静态断言的编译问题 ,深入了解静态断言
27 0
|
20天前
|
算法 编译器 C++
【C++ 关键字的混合使用 】C++深度探索:auto、static、constexpr的交互影响与应用
【C++ 关键字的混合使用 】C++深度探索:auto、static、constexpr的交互影响与应用
29 0
|
22天前
|
算法 编译器 C语言
【C/C++ 关键字 函数说明符 】C/C++ _Noreturn关键字(表明调用完成后函数不返回主调函数)
【C/C++ 关键字 函数说明符 】C/C++ _Noreturn关键字(表明调用完成后函数不返回主调函数)
33 1