【第三天】C++类和对象进阶指南:从堆区空间操作到友元的深度掌握

本文围绕 C++ 展开,介绍了 new 和 delete 对堆区空间的操作,包括基本类型、数组及类对象的空间处理;阐述了静态成员的概念、数据和函数;还讲解了单例模式、类的存储结构、this 指针、const 修饰成员函数以及友元的相关知识,并给出了遥控器类和动态数组类的案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、new和delete 堆区空间操作

1、new和delete操作基本类型的空间

2、 new申请基本类型的数组

 3、new和delete操作类的空间

 4、new申请操作对象数组

 二、静态成员

1、概念

2、静态成员数据

 3、静态成员函数

 三、单例模式

四、类的存储结构

五、this指针

六、const修饰成员函数 

七、友元

1、普通全局函数 作为类的友元

2、 类的某个成员函数 作为另一个类的友元

 3、整个类作为 另一个类的友元

4、案例

(1)遥控器的类

(2)动态数组类


 

一、new和delete 堆区空间操作

1、new和delete操作基本类型的空间

new与C语言中mallocdelete和C语言中free 作用基本相同

 区别:

new 不用强制类型转换

new在申请空间的时候可以 初始化空间内容

2、 new申请基本类型的数组

 3、new和delete操作类的空间

 4、new申请操作对象数组

 二、静态成员

1、概念

类的对象 拥有独立的 普通成员数据。

static 修饰的成员 叫 静态成员。

class Data
{
    int a;//普通成员数据
    static int a;//静态成员数据
    static void func()//静态成员函数
{
}
};

2、静态成员数据

static修饰的静态成员 属于类而不是对象(所有对象 共享 一份 静态成员数据)。

实战案例:使用静态成员数据 统计对象的个数

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
class Data
{
public:
	int mA;//普通成员数据
	static int count;//静态成员数据
public:
	Data()
	{
		count++;
	}
	Data(int a)
	{
		mA = a;
		count++;
	}
	Data(const Data &ob)
	{
		count++;
	}
	~Data()
	{
		count--;
	}
};
//类外初始化
int Data::count = 0;
void test()
{

	Data ob1;
	Data ob2(10);
	Data ob3 = ob2;
	cout << "对象个数:" << Data::count << endl;//3
	{
		Data ob4;
		Data ob5;
		cout << "对象个数:" << Data::count << endl;//5
	}
	cout << "对象个数:" << Data::count << endl;//3
}
int main(int argc, char* argv[])
{
	test();
	return 0;
 }

 3、静态成员函数

静态成员函数直接通过类名称访问

静态成员函数内 只能操作静态成员数据,因为普通成员数据还没有空间。

 三、单例模式

        单例模式可以保证结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。即单例模式的类 只能实例化 一个对象。

        核心:将构造函数私有化

#include <iostream>
using namespace std;
class SingleTon//单例模式
{
//构造私有化 防止实例化其他对象
private:
    SingleTon(){
    count=0;
    cout<<"构造"<<endl;
    }
    SingleTon(const SingleTon &ob){
    count=0;
    }
    ~SingleTon()
    {
    cout<<"析够"<<endl;
    }
private:
    //const防止p 在类内部 被修改指向
    static SingleTon * const p;//保存唯一的实例地址
    int count;//统计任务执行次数
    public:
    static SingleTon * getSingleTon(void)//获取唯一的实例地址
    {
        return p;
    }
    //用户自定义 任务函数
    void printString(char *str)
    {
        count++;
        cout<<"当前第"<<count<<"次任务打印:"<<str<<endl;
    }
};
SingleTon *const SingleTon::p = new SingleTon;//创建唯一的实例

int main(int argc, char *argv[])
{
    //获取单例的地址
    SingleTon *p1 =SingleTon::getSingleTon();
    
    //执行任务
    p1‐>printString("学历证明1");
    p1‐>printString("身份证明1");

    SingleTon *p2 =SingleTon::getSingleTon();
    p2‐>printString("学历证明2");
    p2‐>printString("身份证明2");
}

四、类的存储结构

        成员函数静态成员 是独立存储 是所有对象共享,不占类的空间。

五、this指针

         this是一个隐藏的指针,可以在类的成员函数中使用,它可以用来指向调用对象。当一个对象的成员函数被调用时,编译器会隐式地传递该对象的地址作为 this 指针。

        this 指针是一个特殊的指针,它指向当前对象的实例。每一个对象都能通过 this 指针来访问自己的地址。

        this可以完成链式操作 

六、const修饰成员函数 

        const 修饰成员函数为只读(该成员函数不允许对 成员数据 赋值mutable修饰的成员除外

七、友元

        预知识:将数据和方法封装在一起 加以权限区分 用户只能通过公共方法 操作私有数据。(封装 性)

        定义:一个函数或者类 作为了另一个类的友元 那么这个函数或类 就可以直接访问 另一个类的私 有数据。应用:友元 主要用在运算符重载上

        友元语法:friend关键字只出现在声明处,其他类、类成员函数、全局函数都可声明为友元,友元函数不是类的成员,不带 this指针友元函数可访问对象任意成员属性,包括私有属性。

        现实生活中也可以很好地理解:比如你的家,有客厅,有你的卧室,那么你的客厅是Public的,所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去,但是呢,你也可以允许你的闺蜜好基友进去。程序员可以把一个全局函数、某个类中的成员函数、甚至整个类声明为友元

1、普通全局函数 作为类的友元

2、 类的某个成员函数 作为另一个类的友元

#pragma warning(disable:4996)
#include<iostream>
#include <string>
using namespace std;
class room;//向前声明,只能说明类名称
class Frind
{
public:
	void visiting01(Room& room);
	void visiting02(Room& room);
};
class Room
{
	friend void goodGay::visiting02(Room &room);
private:
	string bedroom;//实例化对象
public:
	string livingroom;
public:
	Room(string bedroom,string livingroom)
	{
		this-> bedroom = bedroom;
		this-> livingroom = livingroom;
	}
};
void test()
{
	Room room("我的卧室", "我的客厅");
	Frind ob;
	ob.visiting01(room);
	ob.visiting02(room);
}
int main(int argc, char* argv[])
{
	test();
	return 0;
 }

void Frind::visiting01(Room& room)
{
	cout << "李四访问到" << room.livingroom << endl;
	//cout<<"李四访问到"<<room.bedRoom<<endl;该成员函数不是类的友元,报错
}

void Frind::visiting02(Room& room)
{
	cout << "好基友张三访问到" << room.livingroom << endl;
	cout << "好基友张三访问到" << room.bedroom << endl;

}

 3、整个类作为 另一个类的友元

         这个类的所有成员函数 都可以访问另一个类的私有数据

#pragma warning(disable:4996)
#include<iostream>
#include <string>
using namespace std;
class room;//向前声明,只能说明类名称
class Frind
{
public:
	void visiting01(Room& room);
	void visiting02(Room& room);
};
class Room
{
	friend class Frind;
private:
	string bedroom;//实例化对象
public:
	string livingroom;
public:
	Room(string bedroom,string livingroom)
	{
		this-> bedroom = bedroom;
		this-> livingroom = livingroom;
	}
};
void test()
{
	Room room("我的卧室", "我的客厅");
	Frind ob;
	ob.visiting01(room);
	ob.visiting02(room);
}
int main(int argc, char* argv[])
{
	test();
	return 0;
 }

void Frind::visiting01(Room& room)
{
	cout << "李四访问到" << room.livingroom << endl;
	cout<<"李四访问到"<<room.bedRoom<<endl;
}

void Frind::visiting02(Room& room)
{
	cout << "好基友张三访问到" << room.livingroom << endl;
	cout << "好基友张三访问到" << room.bedroom << endl;

}

4、案例

(1)遥控器的类

#include <iostream>
using namespace std;
class TV;
class Remote//遥控器类
{
private:
    TV *p;
public:
    Remote(TV *p);
    void offOrOn(void);//开关
    void upVolume(void);//音量
    void downVolume(void);
    void upChannel(void);//频道
    void downChannel(void);

    void showTv(void);
    void setChannel(int channel);
};
class TV
{
    friend void Remote::setChannel(int channel);
    enum{OFF, ON};
    enum{minVol, maxVol=10};
    enum{minChan, maxChan=25};
private:
    int state;
    int volume;
    int channel;
public:
    TV()
    {
        state = OFF;
        volume = minVol;
        channel = minChan;
    }
    void offOrOn(void);
    void upVolume(void);
    void downVolume(void);

    void upChannel(void);
    void downChannel(void);
    void showTv(void);
    };
int main(int argc, char *argv[])
{
    //实例化一个电视机
    TV tv;
    Remote re(&tv);
    re.offOrOn();
    re.upVolume();
    re.upVolume();
    re.upVolume();
    re.setChannel(20);
    re.showTv();
    return 0;
}
void TV::offOrOn()
{
    state = (state==OFF?ON:OFF);
    return;
}
void TV::upVolume()
{
    if(volume == maxVol)
    {
        cout<<"音量已经最大了"<<endl;
        return;
}
    volume++;
    return;
}

void TV::downVolume()
{
    if(volume == minVol)
    {
        cout<<"音量已经最小了"<<endl;
        return;
}
    volume‐‐;
    return;
}
void TV::upChannel()
{
   if(channel == maxChan)
    {
        cout<<"频道已经最大了"<<endl;
        return;
    }
    channel++;
    return;
}

void TV::downChannel()
{
     if(channel == minChan)
    {
        cout<<"频道已经最小了"<<endl;
        return;
    }
    channel‐‐;
    return;
}
void TV::showTv()
{
    cout<<"当前电视机的状态:"<<(state==OFF?"关":"开")<<endl;
    cout<<"当前电视机的音量:"<<volume<<endl;
    cout<<"当前电视机的频道:"<<channel<<endl;
}
Remote::Remote(TV *p)
{
    this‐>p = p;
}
void Remote::offOrOn()
{
    p‐>offOrOn();
}

void Remote::upVolume()
{
    p‐>upVolume();
}
void Remote::downVolume()
{
    p‐>downVolume();
}

void Remote::upChannel()
{
    p‐>upChannel();
}

void Remote::downChannel()
{
    p‐>downChannel();
}

void Remote::showTv()
{
    p‐>showTv();
}
void Remote::setChannel(int channel)
{
    p‐>channel = channel;
}

(2)动态数组类

        根据数据大小动态增减空间。

array.h

#ifndef ARRAY_H
#define ARRAY_H
class Array
{
private:
    int *arr;//存放首元素地址
    int capacity;//容量
    int size;//大小
public:
    Array();
    Array(int capacity);
    Array(const Array &ob);
    ~Array();
    int getCapacity() const;
    int getSize() const;
    void printArray(void);
    //插入尾部元素
    void pushBack(int elem);
    //删除尾部元素
    void popBack(void);
    int &at(int pos);
};

#endif // ARRAY_H

array.cpp

#include "array.h"
#include<string.h>
#include<iostream>
using namespace std;
int Array::getCapacity() const
{
    return capacity;
}

int Array::getSize() const
{
    return size;
}

void Array::printArray()
{
    int i=0;
    for(i=0;i<size; i++)
    {
        cout<<arr[i]<<" ";
    }
    cout<<endl;
    return;
}

void Array::pushBack(int elem)
{
    //判断容器是否满
    if(size == capacity)
    {
        //申请空间
        int *tmp = new int[2*capacity];
        //将就空间的内容 拷贝到新空间
        memcpy(tmp, arr, capacity*sizeof(int));
        //释放原有的空间
        delete [] arr;
        //更新arr的空间
        arr = tmp;
        //更新容量
        capacity = 2*capacity;
    }
    arr[size]=elem;
    size++;
    return;
}
void Array::popBack()
{
    if(size == 0)
    {
        cout<<"容量为空"<<endl;
    }    
    else
    {
        size‐‐;
    }
    return;
}
int& Array::at(int pos)
{
    if(pos<0 || pos >=size)
    {
        cout<<"访问违法内存"<<endl;
        exit(‐1);
    }
    return arr[pos];
}
Array::Array()
{
    capacity = 5;
    size = 0;
    arr = new int[capacity];
    //空间清0
    memset(arr, 0, sizeof(int)*capacity);
}
Array::Array(int capacity)
{
    this‐>capacity = capacity;
    size = 0;
    arr = new int[capacity];
    //空间清0
    memset(arr, 0, sizeof(int)*capacity);
}
Array::Array(const Array &ob)
{
    capacity = ob.capacity;
    size = ob.size;
    //深拷贝
    arr = new int[capacity];
    memcpy(arr, ob.arr, sizeof(int)*capacity);
}
Array::~Array()
{
    if(arr != NULL)
    {
        delete [] arr;
        arr = NULL;
    }
}

main.c

#include <iostream>
#include "array.h"
using namespace std;
int main(int argc, char *argv[])
{
    Array ob;
    cout<<ob.getCapacity()<<" "<<ob.getSize()<<endl;
    ob.pushBack(10);
    ob.pushBack(20);
    ob.pushBack(30);
    ob.pushBack(40);
    ob.printArray();
    cout<<ob.getCapacity()<<" "<<ob.getSize()<<endl;
    ob.pushBack(50);
    ob.pushBack(60);
    ob.printArray();
    cout<<ob.getCapacity()<<" "<<ob.getSize()<<endl;
    ob.popBack();
    ob.popBack();
    ob.printArray();
    cout<<ob.getCapacity()<<" "<<ob.getSize()<<endl;
    cout<<"arr[2] = "<<ob.at(2)<<endl;
    ob.at(2) = 100;
    ob.printArray();
    return 0;
}

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值