当前位置: 首页 > article >正文

C++(类和对象)

C++中的类

C++中兼容对C语言中struct的所有用法.同时C++对struct进行了语法的升级.将struct升级成了类.

// c++中对于struct的改进:
struct Stack
{
	int* a;
	int top;
	int capacity;
}
int main()
{	
	Stack s;// 这里可以直接使用Stack进行使用,而不再需要struct关键字了
	return 0;
}

注意:

  1. 在c++中,类名就是类型,Stack就是类型,不需要加上struct关键字了

  2. 类里面可以定义函数.例如

    // c++中对于struct的改进:
    struct Stack
    {
    	int* a;
    	int top;
    	int capacity;
    
        //可以直接在类中定义函数.
        void Init()
        {
            a = NULL;
            top = 0;
    		capacity = 0;
        }
    
        void Push(int x)
        {
            .....
        }
    }
    int main()
    {	
    	Stack s;// 这里可以直接使用Stack进行使用,而不再需要struct关键字了
        s.Init(); // 直接这样调用函数.
    	return 0;
    }
    

Class的用法

访问限定符:

  • 使用public修饰的符号,在类外可以被访问
  • 使用protected和private修饰的成员在类外面不可以被访问.
  • 访问限定符的作用域 从当前位置开始,直到下一个访问限定符出现为止.如果没有出现下一个访问限定符,那么直接就修饰到结尾.
  • class的访问限定修饰符默认是private,struct默认的是public(为了和C语言适配)

虽然Class中的默认访问限定修饰符的修饰方式是private,但是最好还是将private的成员加上显性的private修饰符.

声明与定义分离

//stack.h文件
#include <iostream>
using namespace std;

class Stack
{
private:
    int *_a;
    int _top;
    int _capacity;

public:
    void Push(int x);
    void Init();
    // 注意:默认在类中定义的函数就是内联函数,前面自动会有一个inline.
    // 但是,如果函数体太长,编译器会忽略inline,将其作为普通函数处理.
    //正确的做法:
    // 长的函数声明与定义分离
    // 短的函数直接在类中定义即可.
    bool Empty()
    {
        return top == 0;
    }
};

// stack.cpp文件
#include"stack.h"

// 声明与定义分离的时候,需要使用Stack::进行修饰
void Stack::Init()
{
    _a = 0;
    _top = 0;
    _capacity = 0;

}
void Stack::Push(int x)
{
    //....
}

// main.cpp文件
#include"stack.h"
int main()
{
    return 0;
}

小技巧:

建议在私有的成员之前或者后面加上_来区分私有成员.

类的作用域

C++中花括号定义的都是域.

类的实例化

注意:在类中的成员:诸如:

class Stack
{
private:
    // 这里的成员都是声明
    int *_a;
    int _top;
    int _capacity;

public:
    void Push(int x);
    void Init();
    // 注意:默认在类中定义的函数就是内联函数,前面自动会有一个inline.
    // 但是,如果函数体太长,编译器会忽略inline,将其作为普通函数处理.
    //正确的做法:
    // 长的函数声明与定义分离
    // 短的函数直接在类中定义即可.
    bool Empty()
    {
        return top == 0;
    }
};
 // main.cpp
int main()
{
	// 此处才是定义对象
	Date d1;
	d1.Empty();
	return 0;
}

类和对象的关系:类就是设计图纸,对象就是建造出来的房子.

注意:同一个类的不同对象中的函数是一样的,但是不同对象中的成员变量是不一样的,函数会被存储到公共的区域中,一旦需要调用函数就直接去这个公共的区域中寻找即可.

类的成员变量的存储还是按照结构体内存对齐法进行对齐的.

注意:就算一个类没有任何成员,这个类的大小是1.(无成员变量的类大小是1字节)

#include"stack.h"
class B{};
int main()
{
    cout<<sizeof(B)<<endl;
    return 0;
}

在这里插入图片描述

无成员变量的类的大小是1字节,这个字节不存储任何数据,只是标识这个类存在过.

#include"stack.h"
class C{
    public:
    void f(){}
};
int main()
{
    cout<<sizeof(C)<<endl;
    return 0;
}

在这里插入图片描述

this指针

类中的成员函数的参数默认第一个是this,但是没有显示的写出来,并且在成员函数中访问成员变量时,前面也会有一个默认的this,例如: this->a.但是this指针不能显式的写实参和形参,可以在类中显式的使用.

#include<iostream>
#include"date.h"
using namespace std;
class Date
{
    private:
        int _year;
        int _month;
        int _day;
    public:
        void Init(int year,int month,int day)
        {
            this->_year=year;
            _month=month;
            _day=day;
        }
        void Print()
        {
            cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
            cout<<this->_year<<"-"<<this->_month<<"-"<<this->_day<<endl;
        }
};
int main()
{
    Date d1;
    d1.Init(2022,10,1);
    d1.Print();
    return 0;
}

那么this指针是存储在哪里的?答:在vs中,this指针是存储在栈帧中的.也就是存储在寄存器中的.

// 这段代码:会正常执行.

#include<iostream>
using namespace std;
class A{
    private:
        int a;
    public:
        void Print(){
            cout<<"A::Print()"<<endl;
        }
};
int main()
{
    A* a = nullptr;
    a->Print();
    return 0;
}

// 但是下面这样子就会运行报错.
#include<iostream>
using namespace std;
class A{
    private:
        int _a;
    public:
        void Print(){
            cout<<_a<<endl;
        }
};
int main()
{
    A* a = nullptr;
    a->Print();
    return 0;
}

默认的6个成员函数

构造函数

构造函数的主要任务并不是开空间,而是初始化对象.

特点:

  1. 函数名和类名相同
  2. 无返回值
  3. 对象实例化时自动调用
  4. 构造函数可以重载
  5. 不写构造函数,编译器会默认生成默认构造函数.这个默认的构造函数:对于内置类型不做处理,对于自定义类型,回去调用它的默认构造函数.(如果没有默认构造函数,就会调用初始化列表)C++11特意对此打了补丁,支持声明时给缺省值.
  6. 无参的构造函数和全缺省的构造函数都称为默认构造函数.并且默认构造函数只能有一个.注意:无参数构造函数,全缺省构造函数.我们没写编译器默认生成的构造函数,都可以认为是默认构造函数.但是:这三个函数不能同时存在,否则会有调用歧义.
#include<iostream>
#include"date.h"
using namespace std;
class Date
{
    private:
        int _year;
        int _month;
        int _day;
    public:
        // 构造函数
        Date(int year,int month,int day)
        {
            _year=year;
            _month=month;
            _day=day;
        }
        // 无参数构造
        Date()
        {
            _year=1;
            _month=1;
            _day=1;
        }

        void Print()
        {
            cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
        }
};
int main()
{
    // 默认调用无参数构造,注意这里不能加括号
    Date d1;
    d1.Print();

    // 主动调用有参数构造
    Date d2(2022,10,1);
    d2.Print();
    return 0;
}

注意:如果没有主动写构造函数的话,编译器会自动生成一个构造函数,但是默认生成的就是随机值.例如

#include<iostream>
#include"date.h"
using namespace std;
class Date
{
    private:
        int _year;
        int _month;
        int _day;
    public:
        void Print()
        {
            cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
        }
};
int main()
{
    
    Date d1;
    // 打印随机值
    d1.Print(); 
    return 0;
}

默认生成的构造函数:

对于自定义类型(class ,struct等),会去调用它的构造函数.

对于内置类型(int/double/指针)的成员不做处理.(例如:Date* 也是内置类型)

但是我们可以在声明的时候给成员变量赋一个缺省值.

#include<iostream>             
#include"date.h"                 
using namespace std;                 
class Date                 
{
    private:                 
    // C++11支持                 
        int _year = 1;                 
        int _month = 1;                 
        int _day = 1;                 
    public:                 
        void Print()                 
        {
            cout<<_year<<"-"<<_month<<"-"<<_day<<endl;                 
        }
};
int main()                 
{
    
    Date d1;
    d1.Print(); 
    return 0;
}
析构函数

功能:对象在销毁时,会自动调用析构函数,完成对象中的资源清理工作.

特点:

  1. 函数名是在类名之前加上~
  2. 无参数返回值类型
  3. 一个对象只能有一个析构函数.若没有显式定义,系统会自动生成默认的析构函数. 注意:析构函数不能重载
  4. 对象声明周期结束时,C++编译系统会自动调用析构函数.

默认生成析构函数的行为与默认生成构造函数相似:

  1. 内置类型成员不做处理
  2. 自定义类型成员会去调用它的析构函数.

http://www.kler.cn/a/503143.html

相关文章:

  • Go语言之路————func
  • 优化神马关键词排名原理(优化神马搜索引擎关键词排名规则)
  • GO语言实现KMP算法
  • 《使用 YOLOV8 和 KerasCV 进行高效目标检测》
  • torch.einsum计算张量的外积
  • 【算法】将单链表按值划分
  • 生成式数据增强在大语言模型中的应用与实践
  • UE5.4运行报错解决(关于osg使用-无法解决的外部命令)(未解决)
  • 优秀持久层框架——MyBatis
  • 两分钟解决 :![rejected] master -> master (fetch first) , 无法正常push到远端库
  • Chromium 中的 WebUI
  • Springboot内置Apache Tomcat 安全漏洞(CVE-2024-50379)
  • vue2修改表单只提交被修改的数据的字段传给后端接口
  • JavaScript:简介
  • 春秋云镜——initial
  • 二 RK3568 固件中打开 ADB 调试
  • qt 汉字输出 中文输出 显示乱码 qDebug() 乱码 解决
  • Spring Boot项目中增加MQTT对接
  • DELTA并联机械手视觉方案荣获2024年度机器人应用典型案例奖
  • 在 Linux 下Ubuntu创建同权限用户
  • JavaScript系列(24)--内存管理机制详解
  • 2025年第三届“华数杯”国际赛A题解题思路与代码(Python版)
  • 计算机网络(四)——网络层
  • 利用 Tree Shaking 提升 React.js 性能
  • 江科大STM32入门——读写备份寄存器(BKP)实时时钟(RTC)笔记整理
  • 【RAG检索增强生成】MaxKB:构建企业级知识库问答系统(Ollama+Qwen2)