类与对象零碎知识点

ops/2024/10/21 22:42:37/

目录

一、构造函数相关知识点补充

1.构造函数体赋值

2.初始化列表

3.explicit关键字

二、static成员 

 三、友元

1.友元函数

2.友元类 


一、构造函数相关知识点补充

1.构造函数体赋值

在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。

虽然调用构造函数后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。

2.初始化列表

初始化列表是C++中用于初始化成员变量的一个特性,在类的构造函数中,可以使用初始化列表来直接初始化成员变量,而不是在构造函数体内进行赋值。

形式:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个成员变量后面跟一个放在括号中的初始值或表达式。

class Date
{
public:
    Date(int year, int month, int day)
        :_year(year)
        ,_month(month)
        ,_day(day)
    {}
private:
    int _year;
    int _month;
    int _day;
};

注意点:

①每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

②类中包含引用成员变量、const成员变量、没有默认构造函数的自定义类型成员(必须显示传参调构造)必须放在初始化列表位置进行初始化

③尽量多使用初始化列表初始化,因为不管是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化

④成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

接下来详细讲解这些点:

关于第②点:

class A
{
public:A(int a):_a(a){}
private:int _a;
};class B
{
public:B(int a, int ref):_aobj(a),_ref(ref),_n(0){}
private:A _aobj;  //没有默认构造函数int& _ref;  //引用const int _n;  //const
};

这段代码中,类B的成员变量_aobj是类A实例化出的一个对象,而A中是没有默认构造函数的,而_ref是引用,_n是const成员变量,所以它们初始化必须在初始化列表中,否则编译器会报错。

 为什么这三种必须要在初始化列表初始化呢?

我们知道,引用必须在定义时初始化,并且一旦被初始化后就不能再被重新赋值,而构造函数体中执行的就是赋值,所以必须在初始化列表中初始化。而const修饰的变量在初始化后是不能被修改的,它也必须在定义时初始化,若执行构造函数体中的赋值语句便是修改了。对于没有默认构造函数的自定义类型,我们不能依赖编译器为我们自动创建对象,必须显式地在初始化列表中为它们提供一个合适的构造函数参数来初始化。

关于第③点: 

初始化列表不管写不写,每个成员都会走一遍,自定义类型的成员会调用它的默认构造函数,如果没有默认构造函数就会报错,内置类型有缺省值就用缺省值,缺省值是给初始化列表用的,没有的话,要看编译器,有的编译器会处理,有的不会。

关于第④点:

先看一段代码:

 在上述代码中,倘若是按照初始化列表中的次序初始化,那最后输出结果应当是1 1,而实际上不是,这就是因为是按照成员变量声明顺序来初始化的。

3.explicit关键字

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换作用。

#include <iostream>
using namespace std;class A
{
public:A(int x):_a(x){}void Print(){cout << _a << endl;}
private:int _a;
};int main()
{A a = 1;a.Print();return 0;
}

最后这段代码的输出结果是1,说明语句A a = 1;是可行的,a跟1类型不一样为什么可以这样写呢?实际上是发生了隐式转换,编译器会先用1构造一个临时对象,然后再调用拷贝构造函数讲临时对象拷贝给a,所以最后是没有问题的。另外,编译器遇到连续构造+拷贝构造会优化为直接构造。

对于只有一个参数的构造函数,我们可以直接用A a = 1;这种形式来写,让它发生隐式转换,对于多个参数的其实也可以,但是就需要用{},例如A a = {1,2,3};。

而explicit关键字主要作用是防止构造函数被用于隐式类型转换,当我们在构造函数前加上explicit关键字后,就不能隐式转换了。

二、static成员 

声明为static的类成员称为类的静态成员,用static修饰的成员变量称为静态成员变量,用static修饰的成员函数称为静态成员函数静态成员变量一定要在类外进行初始化。

特性:

①静态成员为所有类所共享,不属于某个具体的对象,存放在静态区

静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明

③类静态成员可用类名::静态成员或者对象.静态成员来访问

④静态成员函数没有隐藏的this指针,不能访问任何非静态成员

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

⑥静态成员函数只能调用静态成员函数,不能调用非静态成员函数,而非静态成员函数可以调用静态成员函数也可以调用普通成员函数

 假设有一个类A,有一个静态成员变量_a,在类外定义时这样写:int A::_a = 0;

注意:静态成员变量是不能给缺省值的,缺省值是给初始化列表用的,而静态成员变量在静态区,不存在对象中,不走初始化列表。

从这段代码运行结果可以看到,静态成员变量的大小并不包含在类的大小中, 所以说静态成员变量不存在对象中也进一步可以验证了。

还有一个注意点,一般类都写在头文件中,但是静态成员变量不能直接在头文件中直接初始化,因为当有多个源文件时,如果都包含该头文件,就会导致重定义。

 三、友元

1.友元函数

友元函数是通过关键字friend来修饰的,友元函数必须在类的定义中说明,其函数体可以在类内定义,也可以在类外定义。一个函数可以被多个类声明为朋友,这样就可以引用多个类中的私有数据。

注意:

①友元函数可以访问类的私有和保护成员,但是不是类的成员函数

②友元函数不能用const修饰

③友元函数可以在类定义的任何地方声明,不受访问限定符限制

④一个函数可以是多个类的友元函数

⑤友元函数的调用与普通函数的调用原理相同

2.友元类 

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

注意:

①友元关系是单向的,不具有交换性

②友元关系不能传递,例如A是B的友元,B是C的友元,是不能说明A是C的友元的

③友元关系不能继承

示例: 

#include <iostream>
using namespace std;class B
{friend class A;
public:B(int x = 1):_b(x){}
private:int _b;
};class A
{
public:A(int x = 0):_a(x){}void Test(){b._b = _a;}
private:int _a;B b;
};

 内部类:

 概念:如果一个类定义在另一个类的内部,这个类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员,外部类对内部类没有任何优越的访问权限。

注意:内部类就是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员,但是外部类不是内部类的友元。

特性:

①内部类定义在外部类的public、private、protected都可以

②内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名

③sizeof(外部类) = 外部类,和内部类没有任何关系

看一段代码来验证:

#include <iostream>
using namespace std;class A
{
private:static int k;int h;
public:class B // B天生就是A的友元{public:void test(const A& a){cout << k << endl;cout << a.h << endl;}};
};int A::k = 1;int main()
{cout << sizeof(A) << endl;A::B b;b.test(A());return 0;
}

运行结果:

可以看到,sizeof(A)= 4,也就是只算了成员变量h的大小,要访问A类中的静态成员变量k也是可以直接访问。


http://www.ppmy.cn/ops/6030.html

相关文章

探索设计模式的魅力:开启智慧之旅,AI与机器学习驱动的微服务设计模式探索

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索AI与机器学习驱动的微服务设计模式之旅✨ 亲爱的科技爱好者们&#xff0c;有没…

广东海洋大学成功部署(泰迪智能科技)大数据人工智能实验室建设

广东海洋大学简称广东海大&#xff0c;坐落于广东省湛江市&#xff0c;是国家海洋局与广东省人民政府共建的省属重点建设大学、广东省高水平大学重点学科建设高校、粤港澳高校联盟成员 &#xff0c;入选卓越农林人才教育培养计划&#xff0c;是教育部本科教学水平评估优秀院校。…

React + 项目(从基础到实战) -- 第八期

ajax 请求的搭建 引入mockAP接口设计AJAX 通讯 前置知识 HTTP 协议 , 前后端通讯的桥梁API : XMLHttpRequest 和 fetch常用工具axios mock 引入 Mock.js (mockjs.com) 使用 mockJS 前端代码中引入 mockJs定义要模拟的路由 , 返回结果mockJs 劫持ajax请求(返回模拟的结果)…

【ROS2笔记五】ROS2服务通信

5.ROS2服务通信 文章目录 5.ROS2服务通信5.1ROS2中的服务工具5.2 rclcpp实现服务通信5.2.1创建功能包和节点5.2.2服务端实现5.2.3客户端实现 Reference 服务通信也是ROS2中基本的通信方式&#xff0c;服务分为客户端和服务端&#xff0c;由客户端向服务端发送请求&#xff0c;然…

使用Python进行云计算:AWS、Azure、和Google Cloud的比较

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 使用Python进行云计算&#xff1a;AWS、Azure、和Google Cloud的比较 随着云计算的普及&am…

apache是什么

​Apache(音译为阿帕奇)是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上&#xff0c;由于其跨平台和安全性被广泛使用&#xff0c;是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩充&#xff0c;将Perl/Python等解释器编译…

linux限权

shell命令以及运行原理 什么是shell命令&#xff1a; 将使用者的命令翻译给核心&#xff08;kernel&#xff09;处理。同时&#xff0c;将核心的处理结果翻译给使用者。 shell就相当于操作系统外的一层外壳 其实就是登录linux时的一个可执行程序&#xff08;进程&#xff09…

LeetCode刷题总结 | 图论3—并查集

并查集理论基础 1.背景 首先要知道并查集可以解决什么问题呢&#xff1f; 并查集常用来解决连通性问题。大白话就是当我们需要判断两个元素是否在同一个集合里的时候&#xff0c;我们就要想到用并查集。 并查集主要有两个功能&#xff1a; 将两个元素添加到一个集合中。判…