关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

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

发布时间:2023-06-29 12:01:01
四、友元类和友元函数 在类和对象中,我们就已经接触过了,友元函数作用就是,偷家!! 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);中,直接创建一个匿名对象,不担心对他有其他操作,就是一个表达式中连续的步骤,直接优化,不会出现错误。 总结: 类和对象到现在就告一段落了,但是在日后的学习我们还是需要不断地回顾,毕竟知识是连续,联系性比较强的,大家继续加油!后面再见!

/template/Home/leiyu/PC/Static