IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C++】类和对象 -> 正文阅读

[C++知识库]【C++】类和对象

💒前言

??如是初学者,建议按照以下顺序学习
1、C++入门基础

??学习本章 需要掌握C语言中的结构体

🧸面向过程 和面向对象

??对于C语言来说是 面向过程的语言
??C++是面向对象+面向过程,因为C++兼容C
??java是面向对象的语言。
定义
举例:今晚吃 西红柿鸡蛋盖饭
??面向过程:需要自己做,1.切西红柿备用。2.起锅烧油。3.放入鸡蛋炒熟备用…
??面向对象:点了个外卖(西红柿炒鸡蛋盖饭)

💒类和对象(上)

🧸类:

??先看代码 ,后面会解释

class Person //类定义的对象
{
public://访问限定符
//成员函数
void PrintPersonInfo();
private:
//成员变量
char _name[20];
char _gender[3];
int _age;
};

在C中有 struct 定义的结构体

    在C++ 中兼容C 的结果构体,但是已经升级为类
    并且默认访问 是public(公有) 
    而且在结构体中可以定义成员函数 并且调用
    
    struct Stucent
    {
    	//变量
    	char name[10];
    	int age;
    	int id;
    };
    int main()
    {
    	struct Stucent s1; //兼容C
    	strcpy(s1._name, "李四");
    	s1.id = 1;
    	s1.age = 18;
    	printf("%s\n%d\n%d\n",s1.name,s1.age,s1.id);
    }

在C++中用class 定义类

class Stucent
{
public:
	//成员变量
	char _name[10];
	int _age;
	int _id;
	//成员函数
	void Init(const char* name, int age, int id)
	{
		strcpy(_name, name);
		_age = age;
		_id = id;
	}
private:  //以下是私有
	void Print()
	{
		cout << _name << endl;
		cout << _age << endl;
		cout << _id << endl;
	}
};
int main()
{
	Stucent s2;			//升级到类,Stucent类名,也是类型
	strcpy(s2._name, "李四");
	s2._id = 1;
	s2._age = 18;
	s2.Init("张三",18, 1);
	s2.Print();
}

??在C++中用class定义类,类中包含 成员变量、成员函数;
??class中定义的类 是有访问权限的,默认是私有的,外部函数不可以访问

面向对象的三大特性:封装、继承、多态。

??默认访问限定符是private(私有)
??访问限定符:
????public 公有
????protected 保护
????private 私有

访问限定符的作用域
??访问限定符的作用域 遇到下一个限定符结束 或者类的底部结束

类的实例化
??用类名定义的 变量 - 称之为 类实例化的对象

C++类中的成员对象 也就是C结构体中的变量
类对象的大小
??类中有两种对象 - 成员变量 、成员函数
??存储方式 是 实例化对象字存储成员变量、成员函数放在公共代码区,因为 成员函数 是相同的 没必要多处拷贝

// 类中既有成员变量,又有成员函数
class A1 {
public:
	void f1(){}
	private:
	int _a;
};
// 类中仅有成员函数
class A2 {
public:
	void f2() {}
};
// 类中什么都没有---空类
class A3
{};

sizeof(A1) : __4___ sizeof(A2) : __1___ sizeof(A3) : ___1__

类的大小也需要空间对齐,规则与结构体相同
类无变量时 用一个字符标识这个类,存了一个地址

💒类与对象(中)

??六个默认成员函数:构造函数、析构函数、拷贝构造函数、赋值运算符重载

🧸构造函数

??在实例化对象时初始化用的函数,我们自己写了,编译器会调用我们写的,我们不写,编译器会自动生成。对于内置类型成员变量不处理,对于自定义类型成员变量调用它的默认构造函数。

class Date
{
    构造函数 要与定义的类名一致
    1.Date() {}; 不能传参
    2.Date(int a,int b){};必须传参
    3.Date(int a = 0,int b = 0){}; 不传参用缺省值,传参用形参
    
    4.Date(capacaty)//对于栈的初始化
    {
        Stack* ret = (Stack*)malloc(sizeof(Stack)*capacaty)
        _capacaty = capacaty;
    }
};

🧸析构函数

??用于清理对象中的资源,如果独享需要资源,才需要自己实现析构函数,析构函数在函数生命周期到了,自动调用。内置类型不处理,自定义类型调用它的析构函数。

1.对于malloc的对象需要自己定义析构函数
class Stack
{
    int*a;
    int _val;
};
2.对于日期类对象不需要自己定义析构函数
class Date
{
    int _year;
    int _month;
};

🧸拷贝构造函数

??使用同类型的对象去初始化对象,我们不写,编译器自动生成。
??自动生成
????1.内置类型完成按字节序的拷贝 - 浅拷贝 对于指针的拷贝会把指针的地址拷贝过去,造成新初始化的对象与原对象指向同一块空间。
????2.自定义类型的成员变量,调用它的拷贝构造。

1.对于日期类,可以不写,浅拷贝够用
Date(const Date& d) 需要注意这里传引用,不然会死循环调用拷贝构造
{
    _year = d._year;
    _month = d._month;
    _day = d._day;
}

2.对于栈类,需要拷贝构造,因为有指针

3.对于以下,不需要,因为会调用它的拷贝构造
class MyQueue
{
    Stack _pushST;
    Stack _popST;
}

🧸运算符重载

??关键字:返回值类型operator操作符(参数列表)
??自定义类型不支持运算符使用,所以需要自己写
??不能被重载的运算符(5个):.*::sizeof?:.

大于操作符,用引用是为了防止原始数据被改,并可以减少拷贝构造的调用
class Date
{
public:
    bool Date::operator>(const Date& d)
    {
        if(_year>d._year)
            return true;
        else if(_year==d._year && _month>d._month)
            return true;
        else if(_year==d._year && _month==d._month && _day>d._day)
            return true;
        else
            return false;
    }
private:
    int _year;
    int _month;
    int _day;
}

调用:
int mian()
{
    d1 > d2; //d1.operator>(d2)
}
说明:、
如果operator 与main在一个.cpp中 则可以 operator>(d1,d2);这样调用
如果:1.operator>在类中,则字默认增加隐藏参数 this  
    2.所以要减少一个参数,this 就是d1 
    
运算符重载 调用顺序,先去成员函数找,再去全局找

🧸赋值重载

?? 两个已经存在的对象之间 赋值

    Date d1(2022,4,17);
    Date d3(2022,5,23);
    对刚创建的值进行初始化 - 拷贝构造
    Date d4(d1);
    Date d5 = d1;
    
    两个已经存在的对象之间 赋值 - 赋值拷贝
    d1 = d3;

赋值运算符的返回值应该是d1

int i,j,k;
j = i = k = 10;
//k = 10的返回值是k
赋值运算符的实现
Date& operator=(const Date& d)
{
优化:自己个自己赋值 判断一下
    if(this != &d)
    {
        _year = d.year;
        _month = d.month;
        _day = d.day;
    }
    return *this;
}
因为 函数调用结束,d1还存在,所以用引用返回,可以减少拷贝构造


梳理

赋值重载、拷贝构造、构造函数、析构函数分别是干嘛用的?
??1.赋值重载:给两个已经存在的对象进行复制,在这期间会产生临时拷贝,所以会调用拷贝构造,为了减少拷贝构造,参数用了引用参数,因为赋值运算要有返回值作为右值,所以需要返回this参数,,为了减少拷贝构造,返回参数用了引用返回。
??2.拷贝构造:用来对刚创建的对象进行赋值,也用于函数传参,临时拷贝用
??3.构造函数:用于初始化新建的类,一般会用缺省参数,便于创建对象时的赋值。
??4.析构函数:对对象的清理

赋值重载和拷贝构造 代码基本一致
构造函数和析构函数 代码基本一致
以上函数都是 编译器自动调用,不写时自动产生。

  • += 与运算符重载
    ??直接将天数加到 day上 当day小于这个月应该有的天数则结束 返回,如果大于当月天数,则day-当月天数 ,然后进位月份,月份++,当月份>12时 重置为1,年++;
    ??+=是给自身加 比如i=5;i+=10; 则i = 15;
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_month = 1;
			_year++;
		}
	}
	return *this;
}
  • 日期+天数
    ??天数相加 ,+运算符不会改变自身,例如:i= 5; ret = i+10; 最后i还是5 ret是15;,所以这里为了不改变this 先用ret代替*this,在改变ret 返回ret ,又因为ret出函数销毁,所以不能用引用返回,用临时变量(调用拷贝构造,拷贝临时变量)返回
Date Date::operator+(int day)
{
	Date ret = *this;
	ret += day;
	return ret;
}
  • 前置++
    ??前置++ 直接加就可以了 返回原来的值,因为原来的值出作用域补销毁,所以用引用返回。
    ??前置++ 不会进行拷贝 ,建议用前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
  • 后置++
    ??后置++ 为了与前置++区分 多给一个参数int 传什么值不重要
Date Date::operator++(int)
{
	Date ret = (*this);
	*this + 1;
	return ret;
}

**日期类 请单独查看**
析构 在同一个生命周期里 先创建的后析构

🧸const成员

    const 修饰指针
    const* 左面 修饰*p不能改
    const* 右面 修饰p 不能改
    
    void Display() const
    {
        
    }
    void Display(const Date* this)
    {
        
    }
    
    用来修饰 this指针 意思是指针指向的内容不能被修改

🧸取地址及const取地址操作符重载

??这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!

class Date
{
public :
    Date* operator&()
{
    return this ;
}
    const Date* operator&()const
{
    return this ;
}
private :
    int _year ; // 年
    int _month ; // 月
    int _day ; // 日
};

💒类与对象(下)

🧸初始化列表

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

对于引用成员、const成员、自定义类型成员,需要在初始化列表初始化

static成员 初始化,静态变量一定在类外初始化

使用初始化列表可以更高效

Date(const A& aa)
    :_aa(aa)
{}
int main()
{
    A aa(10);
}
上述调用一次拷贝构造 和一次构造函数
Date(const A& aa)
{
    :_aa(aa)
}
int main()
{
    A aa(10);
}
上述调用一次拷贝构造 和两次构造函数
因为初始化列表是成员变量定义的地方,所以_aa会在初始化列表定义的调用默认构造函数初始化

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)

class Sum
{
public:
    Sum()
    {
        _ret += _i;
        ++_i;
    }
    static int GetRet()
    {
        return _ret;
    }
private:
    static int  _i;
    static int _ret;
};
int Sum::_i = 1;
int Sum::_ret = 0;
class Solution {
public:
    int Sum_Solution(int n) {
        //Sum arr[n-1];
        //return Sum().GetRet();
        Sum arr[n];
        return Sum::GetRet();
    }
};
结构体数组 定义的时候n是多少就会调用多少次默认构造函数

🧸C++11 的成员初始化新玩法

private:
    // 非静态成员变量,可以在成员声明时给缺省值。
private:
	int _a1 = 0;  //C++ 11 补丁,给成员变量缺省值
	B _bb;
	B _bb2 = 10;
	B _bb3 = B(10);
	int* p = (int*)malloc(4 * 10);
	//vs2019 支持
	int arr[10] = { 1,2,3,4,5,6,7 };

	// 构造函数 不给静态变量初始化,静态不能这样给缺省值,
	// 必须在类外面全局定义初始化
	//static int _sCount = 0; 
};
这里不是初始化  是缺省值
传参用传参
构造函数有缺省值用构造函数缺省值
最后用成员声明处的缺省值

🧸友元函数

关键字friend
外部函数 在类内使用友元函数则可以访问类内的私有成员变量

friend ostream& operator<<(ostream& _cout, const Date& d);

🧸友元类

Date可以访问Time类

class Time
{
    friend class Date;
}

🧸内部类

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

class A
{
private:
    static int k;
    int h;
public:
    class B
    {
    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.foo(A());
    return 0;
}

💒类和对象完💒

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-28 11:37:29  更:2022-04-28 11:39:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:35:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码