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题进行优化

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


相关文章
|
14天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
46 4
|
15天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
43 4
|
1月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
28 4
|
1月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
25 4
|
1月前
|
存储 编译器 C语言
【C++打怪之路Lv3】-- 类和对象(上)
【C++打怪之路Lv3】-- 类和对象(上)
17 0
|
2天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
14 2
|
8天前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
33 5
|
1月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
22 1
|
1月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)
|
1月前
|
编译器 C++
【C++类和对象(中)】—— 我与C++的不解之缘(四)
【C++类和对象(中)】—— 我与C++的不解之缘(四)