【C++】类和对象(下)(三)

简介: 【C++】类和对象(下)


四、友元类和友元函数

在类和对象中,我们就已经接触过了,友元函数作用就是,偷家!!

class Date
{
  friend inline ostream& operator<<(ostream& out, Date& d)
    ...
private:
   int _year;
   int _month;
   int _day;
};
inline ostream& operator<<(ostream& out, Date& d)
{
  out << d._year << " " << d._month << " " << d._day << endl;
  return out;
}

当定义在类外的函数要使用私有变量时,就可以通过友元函数来访问。友元函数它就是一个普通函数,他没有this指针。

友元类也是偷家,只不过这次换成了类和类直接:

class A
    {
    friend Date B;//友元类
    private:
      int _a;
      static int k;
    public:
       ...
    };
class B
    {
    private:
      int _c;
      int k;
    public:
       ...
    };

B是A的友元类,B能访问A的私有成员变量,但A不能访问B的私有成员变量。(假朋友)

五、内部类(C++中不重要)

就是类套类(类种类)

class A
{
private:
    int _a;
    static int k;
public:
    // B天生就是A的友元
    class B
    {
            int _b;
         void foo(const A& a)
    {
      cout << k << endl;//OK,可以访问
      cout << a._a << endl;//OK
    }
    };
};

1.计算类的内存大小时,sizeof(A)答案是四,因为A对象里没有B,只有自己的成员,这里就可以看作:他们两仅仅是嵌套定义,相当于两个独立的类。


但B类的访问受A类域访问限定符的限制!


A aa;  //aa中没有B的对象


如果要创建一个B的对象,需要 A:: B bb;


只是域限定关系!


2.类种类,被套在里面的类天生是外面类的友元类,B可以访问A,但A不能访问B。


所以定义类时,如果有内部类,你就要小心了,小心不注意把你家偷光!


六、匿名对象

创建类有几种方式呢?

class A
{
public:
    A(int a=0)
    :N(a)
    {}
    int Sum_Solution()
    {
        return N;
    }
private:
    int N;
};
int main()
{
  // 有名对象
  A aa0;
  A aa1(1);
  A aa2 = 2;  //单参数创建类隐式类型转化
  //A aa3(); //不ok,会与函数声明冲突
  // 匿名对象 --生命周期当前这一行
  A();
  A(3);
  //A so;
  //A.Sum_Solution(10);
  A().Sum_Solution(10);
  return 0;
}

匿名对象不需要对象名,且生命周期只是当前这一行。


当我们只是为了访问成员函数,而创建类去访问,那可不可以简单一些呢?


A so;  A.Sum_Solution(10);


A().Sum_Solution(10);   这两个是一样的,这一行结束,匿名对象会自动调用析构函数。


七、编译器中的一些优化

编译器这些优化,只存在于 构造函数和拷贝构造函数之间,且适合一个表达式中的连续步骤,优化的前提当然不能改变原本的正确性!


下面来看几个例子,来了解如何优化,怎么优化:

class A
{
public:
  A(int a = 0)
    :_a(a)
  {
    cout << "A(int a)" << endl;
  }
  A(const A& aa)
    :_a(aa._a)
  {
    cout << "A(const A& aa)" << endl;
  }
  A& operator=(const A& aa)
  {
    cout << "A& operator=(const A& aa)" << endl;
    if (this != &aa)
    {
      _a = aa._a;
    }
    return *this;
  }
  ~A()
  {
    cout << "~A()" << endl;
  }
private:
  int _a;
};
void f1(A aa)
{}
A f2()
{
  A aa;
   //...
  return aa;
}
A f3()
{
  /*A aa(10);
  return aa;*/
  return A(10);
}
int main()
{
  // 优化场景1
  A aa1 = 1;  // A tmp(1) + A aa1(tmp) -> 优化 A aa1(1)
  // 优化场景2
  A aa1(1);
  f1(aa1);
    --------------
  f1(A(1));  // 构造 + 拷贝构造  -> 优化 构造
  f1(1);  // 构造 + 拷贝构造  -> 优化 构造
    //优化场景3
  f2();   // 构造+拷贝构造
  A ret = f2(); // 构造+拷贝构造+拷贝构造 ->优化 构造+拷贝构造,中间可能对aa还有一些操作, 
                  // 不是连续的一个表达式 ,所以无法直接优化为一个构造
    //优化场景4
  A ret;
  ret = f2();
   ----------------
  A ret = f3();  //  构造+拷贝构造+拷贝构造 -> 优化 -> 构造
  return 0;
}

场景1.


前面的单参数隐式类型创建类:


先拿1构造一个临时变量,再用临时变量拷贝aa1(构造+拷贝构造)


优化方式:直接为:A aa1(1);就是构造函数


场景2.


A aa1(1); f1(aa1); 定义一个类,传参调用(构造+拷贝构造),无法优化,不保证是否需要对aa1对象进行操作,所以优化都是一个表达式中的连续步骤。


f1(A(1));  直接利用匿名函数创建类,传值返回。(构造 + 拷贝构造  -> 优化 :构造),因为匿名对象创建完自动析构,就相当于直接拿1去构造了f(1)中的形参 aa了


f1(1);  单参数隐式类型创建对象,1去构造临时变量,临时变量去拷贝形参。( 构造 + 拷贝构造  -> 优化 :构造)


场景3:


f(2)中,先构造一个类,再传值返回,就需要拷贝到临时变量。(构造+拷贝)


A ret = f2();先构造,再拷贝,再拷贝,因为要把返回值拷贝构造到ret对象。(构造+拷贝+拷贝),优化:在拷贝临时变量时,就直接将临时变量当作ret对象拷贝构造了。省略了第三步(构造+拷贝)。


场景4:


A ret; ret = f2();事先创建好了ret对象,ret = f2();不是拷贝构造,是赋值。(构造+拷贝)


A ret = f3();都在一个步骤里。 f3();中创建的是匿名对象,一个构造,后面还是一样,拷贝+拷贝。(构造+拷贝+拷贝)。优化:直接是一个构造函数。

f(3);中,直接创建一个匿名对象,不担心对他有其他操作,就是一个表达式中连续的步骤,直接优化,不会出现错误。

总结:

类和对象到现在就告一段落了,但是在日后的学习我们还是需要不断地回顾,毕竟知识是连续,联系性比较强的,大家继续加油!后面再见!

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