[C++] C++类和对象 类的初始化列表和静态成员 类型转换/友元/内部类/匿名对象/编译器优化

devtools/2024/10/20 7:14:38/

目录

构造函数

1.1 构造函数赋值

1.2 初始化列表

1.3 explicit 关键字

2.类的静态成员

2.1 静态成员函数

2.2 静态成员变量

4.友元

4.1.友元函数

4.2.友元类

5. 内部类

5.1 内部类的概念及特性


构造函数

1.1 构造函数赋值

构造函数是在对象创建时由编译器自动调用为成员变量赋一个初值,你不写编译器默认生成,全缺省的构造函数也是默认构造

当然除了这种方式初始化,还可以通过初始化列表进行初始化

1.2 初始化列表

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

class Date
{
public://初始化列表初始化Date(int year = 1, int month = 1, int day = 1):_year(year),_month(month),_day(day){	}private://成员变量声明int _year;int _month;int _day;
};int main()
{//创建对象Date d1(2022, 5, 22);Date d2;return 0;}

在构造函数中,由编译器在对象创建时自动去初始化列表处完成成员变量的初始化,在对象的生命周期内,初始化列表有且只会进行一次初始化

const类型成员/引用类型成员/没有默认构造的自定义类型的成员,这三类成员必须走初始化列表初始化

对于成员变量,最后都会去初始化列表处初始化

例如,你在成员变量声明时给上缺省值,实际上编译器是在初始化列表处用你给的缺省值去进行初始化

语法:

        类名 ()

        :成员变量(表达式)

        ,成员变量(表达式) { }

class A

{

        A(int a = 0, int b = 0)

        :_a(a)        //以 :开始

        ,_b(b)        //以 , 做分割符

                          //成员变量(),括号内可以是表达式和变量

private:

        int _a = 1;        //C++11

        int _b = 1;        //C++11

};

上面可以看到,在变量声明处和参数列表处都给了缺省值,注意这里的缺省值是不同的

成员变量声明处给的缺省值(C++11支持的)

在你不实现构造函数,编译器调用默认生成的构造函数时,本来是对于内置类型不做处理的,这时候你用了缺省值,编译器就会用你给的这个缺省值初始化 

而参数列表的缺省值,你不去用,对成员变量不会有任何改变

const成员/引用成员/没有默认构造的自定义类型成员为什么要在初始化列表初始?

const成员:        

const成员定义后具有常性,需要赋初值,而编译器对内置类型默认不做处理

引用类型成员:        

引用类型成员在定义时必须指定引用的对象,且不可改变引用的对象,同样的编译器对内置类型默认不做处理

没有默认构造的自定义类型成员:

对于自定义类型,编译器去调它的默认构造函数,如果没有默认构造,就需要你去显示的调用构造

1.3 explicit 关键字

构造函数不仅可以构造与初始化对象,对于单个参数的构造函数,还具有类型转换的作用

class Date
{
public:Date(int year):_year(year){cout << "Date(int year)" << endl;}Date(const Date& d){cout << "Date(const Date& d)" << endl;}private:int _year;
};int main()
{Date d1(2022);//构造Date d2 = 2022;//构造+拷贝构造 ->优化return 0;
}

这里的2022是int类型,而d2是Date类型,此时就会发生类型转换,会创建一个Date的临时对象用这个int值2022去构造,想避免类型转换发生在函数前加上explicit关键字就可以禁止构造函数进行隐式类型转换 

class Date
{
public:explicit Date(int year) :_year(year){cout << "Date(int year)" << endl;}Date(const Date& d){cout << "Date(const Date& d)" << endl;}private:int _year;
};int main()
{Date d1(2022);//构造Date d2 = 2022;//构造+拷贝构造 ->优化return 0;
}

 

使用这种隐式类型转换的代码可读性不是很好,使用explicit可以禁止单参数构造函数进行隐式类型转换

2.类的静态成员

类的静态成员:

静态成员被所有类对象成员共享,不属于某个具体的实例

静态成员和类的普通成员一样,也有 public、protected、private三种访问级别

类静态成员想访问其他静态成员可以通过类名::静态成员或对象.静态成员访问

静态成员函数没有隐含的this指针,不能访问非静态成员

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

2.1 静态成员函数

class A 

{

public:

        static void func()

        {

                //.........

        }

private:
}

因为静态成员不是任何一个对象的,而是属于类的,在对象被实例化前就已经存在。这意味着无论创建多少个类的对象,静态成员都只有一份,被类创建的所有对象共享。

而隐含的this指针则是指向某一个类类型对象,而静态成员处于类本身,所以静态成员没有this指针

2.2 静态成员变量

静态成员变量存储在静态区,被所有的类对象共享,属于整个类。必须在类外进行定义

#include <iostream>
using namespace std;class Date
{
public:static int _count;Date(int year):_year(year){cout << "Date(int year)" << endl;}private:int _year;
};
//静态成员变量在类外定义指定类域
int Date::_count = 10;int main()
{Date d1(2022);cout << d1._count << endl;return 0;
}

4.友元

友元分为友元函数和友元类

友元提供了一种突破封装的方法,有时提供了便利,但这会增加代码之间的耦合度,破坏了封装,所以友元不宜多用

4.1.友元函数

友元函数定义在类外,它可以直接访问类的所有成员,不受访问限定符限制,在函数名前加上friend关键字

class Date
{
public:friend void PrintDate(const Date& d);
private:int _year = 1;int _month = 1;int _day = 1;
};void PrintDate(const Date& d)
{cout << d._year << "/" << d._month << "/" << d._day << endl;
}int main()
{Date d1;PrintDate(d1);return 0;
}

友元函数的说明

  • 友元函数不是类的成员,但可以访问类的所有成员
  • 友元函数可以在类中任意地方声明,不受类的访问限定符限制
  • 友元函数不可以加上const修饰
  • 一个函数可以时多个类的友元
  • 友元函数的调用和普通函数相同

4.2.友元类

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

class Date
{
public:friend class Print;
private:int _year = 1;int _month = 1;int _day = 1;
};class Print
{
public:void PrintDate(const Date& d){cout << d._year << "/" << d._month << "/" << d._day << endl;}
};int main()
{Date d1;Print p;p.PrintDate(d1);return 0;
}

需要注意的是:

1.友元关系是单向的

比如Print类是Date类的友元,可以访问Date的所有成员,但Date类不是Print的友元,无法访问Print的私有和保护成员

2.友元关系不能传递

比如B是A的友元,C是B的友元,这不能说明C是A的友元

5. 内部类

5.1 内部类的概念及特性

内部类的概念:

内部类说白了就是在一个类里面再去定义一个类。所以如果一个类定义在另一个类的内部,这个内部类就叫做内部类。注意此时这个内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去调用内部类。外部类对内部类没有任何优越的访问权限

内部类天生就是外部类的友元

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

内部类的特性:

特性:

1. 内部类可以定义在外部类的 public 、 protected 、 private 都是可以的
2. 注意内部类可以直接访问外部类中的 static 、枚举成员,不需要外部类的对象 / 类名
3. sizeof( 外部类 )= 外部类,和内部类没有任何关系


http://www.ppmy.cn/devtools/127220.html

相关文章

Golang | Leetcode Golang题解之第491题非递减子序列

题目&#xff1a; 题解&#xff1a; var (temp []intans [][]int )func findSubsequences(nums []int) [][]int {ans [][]int{}dfs(0, math.MinInt32, nums)return ans }func dfs(cur, last int, nums []int) {if cur len(nums) {if len(temp) > 2 {t : make([]int, len(…

Linux 内核态,用户态,以及如何从内核态到用户态,交互方式有哪些

一、Linux 内核态&#xff0c;用户态 Linux 内核态&#xff0c;用户态&#xff0c;以及如何从内核态到用户态&#xff0c;我来说下我的理解 很多面试官&#xff0c;面试也是照搬照套&#xff0c;网上找的八股文面试题&#xff0c;面试的人也是背八股文&#xff0c;刚好背到了&…

【日志】关于多益网申

2024.10.19 早先听闻多益的测试题非常抽象&#xff0c;凡是测过的人都说太抽象了&#xff0c;我还以为他考我各种算法或者编程语言呢。我今天也去做了一下&#xff0c;测试题里面大多都考些计算题&#xff0c;找规律题&#xff0c;判断推理题&#xff0c;还有一些图形转换&…

Redis内存淘汰机制!

文章目录 引言内存淘汰策略noevictionallkeys-lruvolatile-lruallkeys-randomvolatile-randomvolatile-ttlvolatile-lfuallkeys-lfu 配置内存淘汰策略实现原理LRU 算法LFU 算法TTL 策略 应用场景性能优化监控与调优实际案例案例 1&#xff1a;社交媒体动态缓存案例 2&#xff1…

rom定制系列------小米6x_MIUI14_安卓13刷机包修改写入以及功能定制 界面预览

在接待一些定制化系统中。有很多工作室或者一些特殊行业的友友需要在已有固件基础上简略修改其中的功能。方便使用。例如usb调试默认开启。usb安装设置以及usb安装与内置删减一些app的定制服务。今天给友友预览其中小米6X此款机型定制相关的一些界面与功能演示。 定制机型以及…

k8s的微服务

ipvs模式 Service 是由 kube-proxy 组件&#xff0c;加上 iptables 来共同实现的 kube-proxy 通过 iptables 处理 Service 的过程&#xff0c;需要在宿主机上设置相当多的 iptables 规则&#xff0c;如果宿主机有大量的Pod&#xff0c;不断刷新iptables规则&#xff0c;会消耗…

mysql connect -- C api编译链接问题,接口介绍(初始化和销毁,连接,执行sql语句,获取结果集的元数据和数据,设置编码格式)

目录 mysql connect 介绍 开发环境 编译链接问题 编译 链接 接口介绍 初始化和销毁 mysql_init() 句柄 mysql_close() 链接数据库 mysql_real_connect() 参数 返回值 show processlist 给mysql下达命令 mysql_query() 参数 返回值 查询结果的获取 引入 …

【LeetCode】每日一题 2024_10_16 最小元素和最大元素的最小平均值(排序、模拟)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 题目&#xff1a;最小元素和最大元素的最小平均值 连续两天的简单题了&#xff0c;我有预感&#xff0c;明天的每日一题估计要来大的了 代码与解题思路 今天的题目算是标准的简单模拟题&#xff0c; 需要…