14-C++面向对象(单例模式、const成员、浅拷贝、深拷贝)

单例模式

        单例模式:设计模式的一种,保证某个类永远只创建一个对象

  1.         构造函数\析构函数 私有化
  2.         定义一个私有的static成员变量指向唯一的那个单例对象(Rocket* m_rocket)
  3.         提供一个公共的访问单例对象的接口(shareRocket())

class Rocket {
private:
	static Rocket* m_rocket;
	Rocket() {}
public:
	static Rocket* shareRocket() {
		//注意考虑多线程安全问题
		if (m_rocket==NULL)
		{
			m_rocket = new Rocket();
		}
		return m_rocket;
	}
	void run() {
		cout << "run()" << endl;
	}
};
Rocket* Rocket::m_rocket = NULL;
int main() {
	Rocket* p = Rocket::shareRocket();
	Rocket* p1 = Rocket::shareRocket();
	Rocket* p2 = Rocket::shareRocket();
	Rocket* p3 = Rocket::shareRocket();
	cout << p << endl;
	cout << p1 << endl;
	cout << p2 << endl;
	cout << p3 << endl;
	p->run();
	return 0;
}

当你需要销毁掉堆里的单例对象时,也需要在类中写一个公共接口

static void deleteRocket() {
        //需要考虑多线程问题
		if (m_rocket != NULL)
		{
			delete m_rocket;
			m_rocket = NULL;//不赋值NULL可以会成野指针。使得重新申请单例对象时出现错误                     
                            //if(m_rocket==NULL)会不成立
		}
	}

为了防止外部直接delete p;而不去通过接口deleteRocket()删除,推荐把析构函数也私有化,完整代码如下:

#include<iostream>
using namespace std; 
/*
单例模式:设计模式的一种,保证某个类永远只创建一个对象
1、构造函数\析构函数私有化
2、定义一个私有的static成员变量指向唯一的那个单例对象
3、提供一个公共的访问单例对象的接口
*/

class Rocket {
private:
	static Rocket* m_rocket;
	Rocket() {}
	~Rocket(){}
public:
	static Rocket* shareRocket() {
		//注意考虑多线程安全问题
		if (m_rocket==NULL)
		{
			m_rocket = new Rocket();
		}
		return m_rocket;
	}
	static void deleteRocket() {
		if (m_rocket != NULL)
		{
			delete m_rocket;
			m_rocket = NULL;
		}
	}
	void run() {
		cout << "run()" << endl;
	}
};
Rocket* Rocket::m_rocket = NULL;
int main() {
	Rocket* p = Rocket::shareRocket();
	Rocket* p1 = Rocket::shareRocket();
	Rocket* p2 = Rocket::shareRocket();
	Rocket* p3 = Rocket::shareRocket();
	cout << p << endl;
	cout << p1 << endl;
	cout << p2 << endl;
	cout << p3 << endl;
	p->run();
	Rocket::deleteRocket();
	return 0;
}

const成员

  const成员:被const修饰的成员变量、非静态成员函数

const成员变量

  1. 必须初始化(类内部初始化),可以在声明的时候直接初始化赋值
  2. 非static的const成员变量还可以在初始化列表冲初始化

const成员函数

  1. const关键字写在参数列表后面,函数的声明和实现都必须带const
  2. 内部不能修改非static成员变量
  3. 内部只能调用const成员函数、static成员函数
  4. 非const成员函数可以调用const成员函数
#include <iostream>
using namespace std;

class Car
{
	int m_price;
	void run() const {
		cout << "run()" << endl;
		m_price = 0;//error
	}
};
int main() {

	return 0;
}

 引用类型成员

  1. 引用类型成员变量必须i初始化(不考虑static情况)
  2. 在声明的时候直接初始化
  3. 通过初始化列表初始化

拷贝构造函数

  1. 拷贝构造函数是构造函数的一种
  2. 当利用已存在的对象创建一个新对象是(类似于拷贝),就会调用新对象的拷贝函数进行初始化
#include <iostream>
using namespace std;
class Car {
	int m_price;
	int m_length;
public:
	Car(int price = 0, int length = 0) :m_price(price), m_length(length) {
		cout << "Car(int price = 0, int length = 0) :m_price(price)" << endl;
	}
	//拷贝构造函数
	Car(const Car& car):m_price(car.m_price),m_length(car.m_length) {
		cout << "const Car& car" << endl;
		}
	void display() {
		cout << "price=" << m_price << ",length=" << m_length << endl;
	}
};


int main() {
	Car car1;
	Car car2(100, 200);
	//拷贝构造函数,利用已经存在的car2对象创建了一个car3对象
	//car3初始化时会调用拷贝构造函数
	Car car3(car2);
	car3.display();

	return 0;
}

浅拷贝、深拷贝

编译器默认的提供的拷贝是浅拷贝(shallow copy)

  1. 将一个对象中所有成员变量的值拷贝到另一个对象
  2. 如果某个成员变量是个指针,只会拷贝指针中存储的地址值,并不会拷贝指针指向的内存空间
  3. 可能会导致堆空间多次free的问题

如果需要实现深拷贝(deep copy),就需要自定义拷贝构造函数

  1. 将指针类型的成员变量所指向的内存空间,拷贝到新的内存空间

下面这个例子是说浅拷贝导致了堆空间的变量指向了栈空间,不安全

#include<iostream>
using namespace std;
class Car {
	int m_price;
	char* m_name;
public:
	Car(int price = 0, char* name = NULL):m_price(price),m_name(name) {}
	void display() {
		cout << "price is " << m_price << ",name is " <<m_name<< endl;
	}
};
int main() {
	const char* name = "bmw";
	char name2[] = { 'b','m','w','\0' };
	cout << name2 << endl;
	cout << strlen(name) << endl;

	Car *car = new Car(100, name2);
	car->display();
	return 0;
}

深拷贝,连同所指向的内存空间也拷贝了

#include<iostream>
using namespace std;
class Car {
	int m_price;
	char* m_name;
public:
	Car(int price = 0, const char* name = NULL) :m_price(price){
		if (name == NULL) return;
		//申请新的堆空间
		m_name = new char[strlen(name) + 1]{};
		//拷贝字符串数据到新的堆空间
		strcpy(m_name, name);
	}
	~Car() {
		if (m_name == NULL) return;
		delete m_name;
		m_name = NULL;
	}
	void display() {
		cout << "price is " << m_price << ",name is " << m_name << endl;
	}
};

int main() {
	const char* name = "bmw";
	char name2[] = { 'b','m','w','\0' };
	cout << name2 << endl;
	cout << strlen(name) << endl;

	Car* car = new Car(100, name);
	car->display();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_56728342/article/details/129806269