类和对象复习

类和对象

1.面向对象和面向过程的区别

面向对象:是将事务抽象成类和对象,以对象为中心,通过对象的交互实现程序的功能 , 可维护性强

面向过程: 是将复杂问题一步步拆分,通过依次执行来解决问题 , 可维护性比较弱

2.类大小的计算

1.内存对齐

考虑内存对齐的默认大小 vs默认是 8字节 对齐是默认对齐数 和 数据类型的最小值 对齐可以使用 #pragma pack(n)来调整对齐数

   #include <stdio.h>

   #pragma pack(4) //对齐数为4
   struct MyStruct {
       char a;
       int b;
   };
   #pragma pack()

   int main() {
       printf("Size of MyStruct: %d\n", sizeof(struct MyStruct));
       return 0;
   }

也可以是用alignas 关键字进行修改

	alignas(16) int b;

变量 b 将按照 16 字节对齐。

2.空类

空类大小会被编译器设置为1字节大小

主要是保证每一个实例的独一无二的地址,如果空类的地址为0,那么多个空类对象地址会出现重叠,就会无法导致正确区分这些类

3.class和struct

class默认权限是private struct默认权限是public

class默认继承权限是private struct默认继承权限是public

class用来定于复杂的数据类型

struct用于数据类型的聚合

4.this指针

this指针是隐藏在非静态成员函数的特殊指针类型,它指向正在调用的该成员函数的对象实例

可以用来区别成员变量 和 局部变量 可以用this->加上成员变量名

this一般是隐式传递的 也可以取地址拿到this指针地址,也可以delete this 但是一般不推荐很危险

如果在析构函数中调用delete this 会造成无线递归死循环析构

5.8个默认成员函数

1.构造和析构
1.构造函数

在创建出实例对象的时候会自动调用构造函数对其成员变量进行初始化,初始化分为列表初始化,和函数体初始化

列表初始化是在分配内存时就进行初始化,函数体初始化是在分配完内存后再进行赋值初始化

如果没有显式的写出构造函数,编译器会生成默认的构造函数

2.析构函数

在delete对象时会先调用析构函数进行申请的内存释放

同上如果没有显式析构函数会生成默认的析构函数

2.拷贝构造和赋值
1.拷贝构造

拷贝构造是特殊的成员函数,用于把一个已有的同类对象去对一个创建的新对象进行初始化操作

class MyClass {
public:
    MyClass(const MyClass& other);  // 拷贝构造函数的声明
    // 其他成员函数和数据成员
};

默认情况下编译器生成的是浅拷贝,只是简单的值复制,会造成资源重复释放的问题,会报错

一般情况下我们需要自定义拷贝构造不仅复制值还要复制指针所指向的内容,确保每个对象有独立的空间

   class DeepCopyExample {
   public:
       int* data;
       DeepCopyExample(int value) {
           data = new int(value);
       }
       // 自定义的拷贝构造函数(深拷贝)
       DeepCopyExample(const DeepCopyExample& other) {
           data = new int(*other.data);
       }
       ~DeepCopyExample() {
           delete data;
       }
   };
2.赋值

赋值通常是通过重载operator = 将一个已有的对象赋值给另一个已有的同类型对象

3.移动构造和移动赋值
1.移动构造

通过move()移动语义 将其转换成一个将亡值 移动构造参数为一个右值引用将其接受,是一种高效的资源转移手段

调用时机 – 放一个临时对象被用于初始化另一个同类型对象时,编译器会优先调用移动构造函数,如果定义了的话

ResourceHolder createResourceHolder() {
    return ResourceHolder();
}

int main() {
    ResourceHolder obj1;
    obj1 = createResourceHolder(); // 这里可能调用移动赋值运算符,如果定义了的话;如果没有定义移动赋值运算符但有移动构造函数,可能会先调用移动构造函数创建一个临时对象,然后调用拷贝赋值运算符(如果定义了)或默认的拷贝赋值运算符。

    ResourceHolder obj2(std::move(obj1)); // 显式调用移动构造函数,将 obj1 的资源转移到 obj2
    return 0;
}
2.移动赋值

移动赋值和移动构造类似都是资源高效的一种资源转移的手段

调用时机 当使用一个右值进行赋值的时候会调用移动赋值

   class ResourceHolder {
   public:
       int* data;

       // 移动赋值运算符
       ResourceHolder& operator=(ResourceHolder&& other) {
           if (this!= &other) {
               delete data;  // 释放当前对象原有的资源
               data = other.data;  // 窃取源对象的资源
               other.data = nullptr;  // 将源对象置为可安全销毁状态
           }
           return *this;
       }
   };
4.初始化列表
1.特性是什么?

初始化列表是在构造函数后面的 的 :后面进行初始化 初始化顺序是按声明顺序进行初始化的不是按初始化列表初始化的 ; 在对象调用构造函数初始化分配内存的时候,就同时初始化,而函数体初始化是在分配完成后在进行赋值初始化;效率上是比较高的

2.哪些成员必须在初始化列表进行初始化?

const成员变量 和引用必须初始化 一个是常量 一个是别名 比如进行初始化

3.初始化顺序是按声明顺序
5.运算符重载
1.哪些运算符不能重载

一些原来没有的运算符不能重载我们不能自己造一个运算符出来重载

2.和函数重载有什么区别

函数重载是通过参数列表不同进行重载 ,运算符重载需要通过operator关键字进行重载

3.他的意义是什么

运算符重载主要是能让我们对自定义类型像内置类型一样进行+ - * 等运算

6.友元
1.友元类

友元类是一种特殊的类关系设定,允许一个类访问另一个类的保护成员和私有成员,只需要在内类声明友元类就行,就好像是自己的成员一样访问;

同样也是用friend关键字修饰就行

class ClassB; // 前置声明

class ClassA {
private:
    int privateDataA;
public:
    ClassA();
    // 将 ClassB 声明为友元类
    friend class ClassB;
};

class ClassB {
public:
    ClassB();
    void accessClassA(ClassA& obj);
};

可以增强代码的复用,提高代码的执行效率,但同时也破坏了封装可以直接通过友元类进行私有成员的访问,可能会导致数据的不安全等因素;

2.友元函数

友元函数是一种特殊的非成员函数,通过friend关键字修饰可以访问类的保护成员和私有成员

class Myclass
{
public:
	Myclass();
	friend void friendFunction(Myclass& obj); //友元函数
private:
	int privateData;
};

增强了可访问行可以外部访问内部,但是同时也破坏了封装性,增加了代码的耦合度

7.static成员

static成员函数

static成员函数属于类不属于对象,没有this指针,不能访问其他类成员函数和成员变量,只能访问static成员函数和静态数据成员 , 只能通过类名::进行访问 , 同样也具有隐藏性;

可以用于实现单例

   class Singleton {
   private:
       static Singleton* instance;
       Singleton() {
           // 私有构造函数,防止外部直接实例化
       }
   public:
       static Singleton* getInstance() {
           if (instance == nullptr) {
               instance = new Singleton();
           }
           return instance;
       }
   };

   Singleton* Singleton::instance = nullptr;

static数据成员

静态数据成员所有对象共享一个数据成员 需要在类外进行初始化,静态数据成员在程序开始运行时就分配内存空间一般在静态区和全局变量一样 ;主要分为初始化 和 未初始化 , 初始化一般在.data 区 未初始化会被初始化为0 存在.bss区 ,生命周期伴随整个程序,只在当前文件可见 具有隐藏性

8.对象拷贝时编译器优化

主要是减少拷贝不用去创建临时对象,而是直接在用户调用栈进行对象创建

   class MyClass {
   public:
       MyClass(int a) : data(a) {}
       MyClass(const MyClass& other) : data(other.data) {
           std::cout << "Copy constructor called." << std::endl;
       }
       int data;
   };

   MyClass createObject(int value) {
       MyClass obj(value);
       return obj;
   }

在没有返回值优化的情况下会现在函数内部创建一个临时对象,然后从临时对象拷贝到调用栈,在有返回值优化的情况下时直接在调用栈进行对象的创建省去拷贝过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值