首页 > 编程语言 >C++笔记4•类和对象3•

C++笔记4•类和对象3•

时间:2024-08-14 22:58:48浏览次数:10  
标签:初始化 对象 成员 笔记 month int C++ year day

1.初始化列表

(1)构造函数再理解:

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

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

(2)初始化列表定义:

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

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

 }
private:
 int _year;
 int _month;
 int _day;
};
说明:

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

    2)类中包含以下成员,必须放在初始化列表位置进行初始化:

         • 引用成员变量          • 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(10)
 {}
private:
 A _aobj;      // 没有默认构造函数
 int& _ref;    // 引用
 const int _n; // const 
};
(3) 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量, 一定会先使用初始化列表初始化。 (4) 成员变量 在类中 声明次序 就是其在初始化列表中的 初始化顺序 ,与其在初始化列表中的先后次序无关,所以最好将 类中声明次序 初始化列表中的初始化顺序 一致,这样不易出错。
class A
{
public:
    A(int a)
       :_a1(a)
       ,_a2(_a1)
   {}
    
    void Print() {
        cout<<_a1<<" "<<_a2<<endl;
   }
private:
    int _a2;
    int _a1;
};
int main() {
    A aa(1);
    aa.Print();//输出1  随机值
}

这个代码出错原因就是类中声明次序初始化列表中的初始化顺序不一致造成的。应修改为

class A
{
public:
    A(int a)
       :_a1(a)
       ,_a2(_a1)
   {}
    
    void Print() {
        cout<<_a1<<" "<<_a2<<endl;
   }
private:
    int _a1;
    int _a2;
};
int main() {
    A aa(1);
    aa.Print();//输出 1  1
}

2.explicit关键字

构造函数不仅可以构造与初始化对象, 对于单个参数或者除第一个参数无默认值其余均有默认值 的构造函数,还具有类型转换的作用 。见下方代码
class Date
{
public:
 // 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用
 // explicit修饰构造函数,禁止类型转换---explicit去掉之后,代码可以通过编译
 explicit Date(int year)
 :_year(year)
 {}

 /*
 // 2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用explicit修饰,具
有类型转换作用
 // explicit修饰构造函数,禁止类型转换
 explicit Date(int year, int month = 1, int day = 1)
 : _year(year)
 , _month(month)
 , _day(day)
 {}
 */
 Date& operator=(const Date& d)
 {
 if (this != &d)
 {
 _year = d._year;
 _month = d._month;
 _day = d._day;
 }
 return *this;
 }
private:
 int _year;
 int _month;
 int _day;
};
void Test()
{
 Date d1(2023);
 d1 = 2024;
 // 用一个整形变量给日期类型对象赋值
 // 实际编译器背后会用2024构造一个临时的无名对象,最后用无名对象给d1对象进行赋值
 // 将1屏蔽掉,2放开时则编译失败,因为explicit修饰构造函数,禁止了单参构造函数类型转
换的作用
}

 3.static成员

(1)概念: 声明为 static 的类成员 称为 类的静态成员 ,用 static 修饰的 成员变量 ,称之为 静态成员变量 ;用 static 修饰成员函数 ,称之为 静态成员函数静态成员变量一定要在 类外进行初始化,类内进行声明。
//使用static成员 计算创建对象的个数
class A
{
public:
	A() 
	{ ++_scount; //构造函数
	}
	A(const A& t) 
	{
		++_scount;//拷贝构造函数
	}
	~A() 
	{ --_scount; //析构函数
	}
	static int GetACount() //static修饰的成员函数 没有了this指针
	{ 
		return _scount;
	}
private:
	static int _scount;//静态成员变量在类内进行声明
};

int A::_scount = 0;//静态成员变量在类外进行初始化

void TestA()
{
	cout << A::GetACount() << endl;
	A a1, a2;
	A a3(a1);
	cout << A::GetACount() << endl;
}

int main()
{
	TestA();
    return 0;
}
(2) 特点;         1. 静态成员所有类对象所共享 ,不属于某个具体的对象,存放在静态区         2. 静态成员变量 必须在 类外定义 ,定义时不添加 static 关键字,类中只是声明             我们可以使用static关键字来把类成员定义为静态的。当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。静态成员在类的所有对象中是共享的。如果不存在其他的初始化语句,在创建第一个对象时,所有的静态数据都会被初始化为零。我们不能把静态成员的初始化放置在类的定义中,但是可以在类的外部通过使用范围解析运算符::来重新声明静态变量从而对它进行初始化。( 类内声明,必须类外初始化(定义) )         3. 类静态成员即可用 类名 :: 静态成员 或者 对象 . 静态成员 来访问            也是就突破类域的两种方式:类名 :: 静态成员 或者 对象 . 静态成员             比如:(  有一个class Date的类,创建一个对象d,访问函数f();要想访问f:             Date::f()  或 d.f()    )         4. 静态成员函数 没有 隐藏的 this 指针 ,不能访问任何非静态成员         5. 静态成员也是类的成员,受 public 、 protected 、 private 访问限定符的限制 【注意】         1)静态成员函数不可以调用非静态成员函数,只可以调用静态成员函数         2)非静态成员函数可以调用类的静态成员函数或非静态成员函数。

 4.友元

(1)概念:

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。 友元分为:友元函数友元类 (2) 友元函数: 当重载 operator<< ,会发现将 operator<< 重载成成员函数,会出现一些小问题。 因为 cout 输出流对象和隐含的 this 指针在抢占第一个参数的位置 。 this 指针默认是第一个参数也就是左操作 数了。但是实际使用中cout 需要是第一个形参对象,才能正常使用。所以要 operator<< 重载成 全局函数 。但又会导致类外没办法访问成员,此时就需要 友元来解决, 见下方代码
class Date
{
public:
	Date(int year=1, int month=1, int day=1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	ostream& operator<<(ostream& _cout)
	{
		_cout << _year << "-" << _month << "-" << _day << endl;
		return _cout;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	d1 << cout;//正常应该是  cout << d1;
	// d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用,正常应该是
	// 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧
}

解决方案:友元函数

//用友元函数解决

class Date
{
 friend ostream& operator<<(ostream& _cout, const Date& d);//前面加上friend 类内声明
 friend istream& operator>>(istream& _cin, Date& d);
public:
 Date(int year = 1900, int month = 1, int day = 1)
 : _year(year)
 , _month(month)
 , _day(day)
 {}
private:
 int _year;
 int _month;
 int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)//类外定义,这样就可以访问类的私有成员变量
{
 _cout << d._year << "-" << d._month << "-" << d._day;
 return _cout; 
}
istream& operator>>(istream& _cin, Date& d)
{
 _cin >> d._year;
 _cin >> d._month;
 _cin >> d._day;
 return _cin;
}
int main()
{
 Date d;
 cin >> d;
 cout << d << endl;
 return 0;
}
说明:      1)友元函数可访问类的私有和保护成员,但不是类的成员函数      2)友元函数不能用const修饰    3)友元函数可以在类定义的任何地方声明,不受类访问限定符限制    4)一个函数可以是多个类的友元函数    5)友元函数的调用与普通函数的调用原理相同    

(2)友元类:

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员
  • 友元关系是单向的,不具有交换性。
       比如下方 Time 类和 Date 类,在 Time 类中声明 Date 类为其友元类,那么可以在 Date 类中直接 访问Time 类的私有成员变量,但想在 Time 类中访问 Date 类中私有的成员变量则不行。
  •   友元关系不能传递
         如果 C 是 B 的友元, B 是 A 的友元,则不能说明 C 时 A 的友元。
  • 友元关系不能继承,在继承位置再详细介绍。
  • class Time
    {
       friend class Date; //声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
    public:
     Time(int hour = 0, int minute = 0, int second = 0)
     : _hour(hour)
     , _minute(minute)
     , _second(second)
     {}
       
    private:
       int _hour;
       int _minute;
       int _second;
    };
    class Date
    {
    public:
       Date(int year = 1900, int month = 1, int day = 1)
           : _year(year)
           , _month(month)
           , _day(day)
       {}
       
       void SetTimeOfDate(int hour, int minute, int second)
       {
           // 直接访问时间类私有的成员变量
           _t._hour = hour;
           _t._minute = minute;
           _t._second = second;
       }
       
    private:
       int _year;
       int _month;
       int _day;
       Time _t;
    };

5. 内部类(C++用的很少)

(1)概念: 如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类, 它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越 的访问权限。内部类就是外部类的友元类。 (2)特点:         1) 内部类可以定义在外部类的 public 、 protected 、 private 都是可以的。         2) 注意内部类可以直接访问外部类中的 static 成员,不需要外部类的对象 / 类名。         3) sizeof( 外部类 )= 外部类,和内部类没有任何关系。
class A
{
private:
 static int k;
 int h;
public:
 class B // B天生就是A的友元
 {
 public:
 void foo(const A& a)
 {
 cout << k << endl;//OK
 cout << a.h << endl;//OK
 }
 };
};
int A::k = 1;
int main()
{
    A::B b;// 不能B b; 要先从A中找到内部类B,在创建对象
    b.foo(A());
    
    return 0;
}

标签:初始化,对象,成员,笔记,month,int,C++,year,day
From: https://blog.csdn.net/qq_64446190/article/details/141123614

相关文章

  • 笔记本电脑本地部署ollama大模型(显存不足调用CUDA Unified Memory方法)
    软硬件:win11,NVIDIAGeForceRTX3050显存4g一.ollama模型最低要求1.Llama3.1(8B)模型GPU:至少需要1张具有16GB显存的GPU(例如NVIDIATeslaV100或A100)。CPU:高性能的多核处理器(例如IntelXeon或AMDRyzen)。内存:最少32GB的系统内存。存储:需要大约......
  • 推荐系统三十六式学习笔记:工程篇.效果保证31|推荐系统的测试方法及常用指标介绍
    目录为什么要关注指标推荐系统的测试方法1.业务规则扫描2.离线模拟测试3.在线对比测试4.用户访谈常用指标1.系统有多好?假设你已经有了自己的推荐系统,这个系统已经上线。为什么要关注指标面对推荐系统这样一个有诸多复杂因素联动起作用的系统,要时时刻刻知道它好不......
  • 2024华为OD机试真题-启动多任务排序(C++/Python)-C卷D卷-200分
    2024华为OD机试题库目录(Python、C++)-(C卷+D卷)-CSDN博客目录题目描述输入描述输出描述用例1题目解析代码c++python题目描述一个应用启动时,会有多个初始化任务需要执行,并且任务之间有依赖关系,例如A任务依赖B任务,那么必须在B任务执行完成之后,才能开始执行A任务。......
  • Java 中的面向对象编程 (OOP) 概念
    前言顾名思义,面向对象编程或JavaOOP概念是指在编程中使用对象的语言,它们使用对象作为实现代码中要发生的事情的主要来源。对象由查看者或用户看到,执行您分配的任务。面向对象编程旨在在编程中实现现实世界中的实体,如继承、隐藏、多态性等。OOP的主要目的是将数据和操作......
  • 【树莓派学习笔记2】opencv常用的视觉方案,特征颜色提取,模式匹配,图形映射函数
    本文主要介绍opencv里面一些常用的视觉方案,所需的全部代码均在如下1.给视觉单独开一个进程持续运行并更新全局变量#获取并处理图像defget_image():whileTrue:#开全局变量处理,分理处红绿蓝globalimage,image_red,image_green,image_blue......
  • 基于STM32的边缘计算实时数据处理可视化系统:嵌入式C++、 FreeRTOS、Kafka、Spring Bo
    一、项目概述本项目旨在设计并实现一个基于STM32的边缘计算实时数据处理系统。该系统能够在边缘设备端进行数据采集、预处理,并将处理后的数据实时传输到后端服务器进行进一步分析和存储。本项目主要解决以下问题:减轻后端服务器的数据处理负担,提高系统整体效率降低......
  • 网络安全学习笔记
    Web介绍Web全称WorldWideWeb,全球广域网,也称为万维网。Web项目分为C/S架构和B/S架构。C/S架构:全称客户端服务端架构,client/server。服务端主要负责加工处理数据,客户端主要用来展示数据。有些数据存在服务端,有些数据存在客户端。B/S架构:是C/S架构的一种,浏览器/服务器架构,br......
  • js数组对象去重
    核心方法:对象属性排序:Array.sort()string和number类型的数组去重:newSet()代码部分1functionuniqueArr(arr){2letresult=[];3arr.forEach(item=>{4result.push(sortObjProperty(item));5});6result=[...(newSet(result.ma......
  • 【面试】分别解释一下C++、Java、Python程序的执行过程
    面试模拟场景面试官:你能分别解释一下C++、Java、Python程序的执行过程吗?参考回答示例1.C++程序的执行过程1.1编译过程:源代码编写:开发者编写C++源代码,文件扩展名为.cpp。预编译(Preprocessing):预编译是编译的第一步,使用预处理器(如cpp)对源代码进行处理。这一步主......
  • Datawhale X 魔搭 AI夏令营 AIGC方向 task2笔记
       纯小白,自学!从零入门AI生图(AIGC方向)基于魔搭社区“可图Kolors-LoRA风格故事挑战赛”开展实践学习。#DatawhaleX魔搭AI夏令营#一、利用AI精读baseline学习代码   task2的目的是精读baseline,从代码层面理解AI生图,直播演示了用通义千问解析代码,我也用GPT-4o,文心......