【C++】特殊类设计

这篇具有很好参考价值的文章主要介绍了【C++】特殊类设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C++】特殊类设计,C++,c++,开发语言,特殊类设计

欢迎来到Cefler的博客😁
🕌博客主页:折纸花满衣
🏠个人专栏:题目解析
🌎推荐文章:【LeetCode】winter vacation training

【C++】特殊类设计,C++,c++,开发语言,特殊类设计


👉🏻设计一个类,不能被拷贝

拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可

🌸 C + + 98 C++98 C++98
将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。

class CopyBan
{
    // ...
    
private:
    CopyBan(const CopyBan&);
    CopyBan& operator=(const CopyBan&);
    //...
};

原因

  1. 设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不
    能禁止拷贝了
  2. 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写
    反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。

🌸 C + + 11 C++11 C++11
C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上
=delete,表示让编译器删除掉该默认成员函数

class CopyBan
{
    // ...
    CopyBan(const CopyBan&)=delete;
    CopyBan& operator=(const CopyBan&)=delete;
    //...
};

👉🏻设计一个类,只能在堆上创建对象

实现方式:

  1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
  2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
class HeapOnly    
{     
public:     
    static HeapOnly* CreateObject()  
   {      
        return new HeapOnly;    
   }
private:    
    HeapOnly() {}
    
    // C++98
    // 1.只声明,不实现。因为实现可能会很麻烦,而你本身不需要
 // 2.声明成私有
    HeapOnly(const HeapOnly&)// or
        
    // C++11    
    HeapOnly(const HeapOnly&) = delete;
};

👉🏻设计一个类,只能在栈上创建对象

方法:将构造函数私有化,然后设计静态方法创建对象返回即可。

class StackOnly
{
public:
 static StackOnly CreateObj()
 {
 return StackOnly();
 }
    
    // 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉
 // StackOnly obj = StackOnly::CreateObj();
 // StackOnly* ptr3 = new StackOnly(obj);
 void* operator new(size_t size) = delete;
 void operator delete(void* p) = delete;
private:
 StackOnly()  
 :_a(0)
 {}
private:
 int _a;
};

只能在栈上或堆上创建对象采用的方法都是类似的,就是将构造函数私有化,自己创建一个静态成员函数,也就是说该对象如何被创建出来取决于这个静态成员函数内部如何进行对象创建。

👉🏻设计一个类,不能被继承

🌸 C + + 98 C++98 C++98

// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{
public:
 static NonInherit GetInstance()
 {
 return NonInherit();
 }
private:
 NonInherit()
 {}
};

🌸 C + + 11 C++11 C++11
final关键字,final修饰类,表示该类不能被继承

class A  final
{
    // ....
};

👉🏻设计一个类,只能创建一个对象(单例模式)

🥱单例模式概念
单例模式是一种创建型设计模式,它保证一个类只有一个实例,且提供全局访问点

在使用单例模式时,我们通过限制类的构造函数和使用一个静态变量来确保只有一个实例。通常情况下,我们会将这个静态变量定义为私有静态成员变量,只能通过类的静态方法来获取这个实例。这个静态方法通常被称为“获取实例的方法”或“工厂方法”。

单例模式常用于需要全局唯一实例的场景,例如配置信息、日志记录器、数据库连接池等。

单例模式有两种实现模式:

饿汉模式

饿汉模式(Eager Initialization): 在饿汉模式下,单例实例在程序启动时就被创建,因此它是线程安全的。具体实现如下:

class Singleton {
private:
    static Singleton instance; // 在类加载时创建实例

    Singleton() {} // 私有构造函数

public:
    static Singleton& getInstance() {
        return instance;
    }
     
    // 其他方法...
};

Singleton Singleton::instance; // 类加载时创建实例

// 使用示例
int main() {
    Singleton& singleton = Singleton::getInstance();
    //...

    return 0;
}

在上述代码中,我们将单例实例定义为一个私有的静态成员变量instance,并且在其声明时直接初始化为Singleton类的实例。通过公共的静态方法getInstance来获取该实例。由于静态成员变量在类加载时就被初始化,所以在多线程环境下也能保证只有一个实例被创建。

饿汉模式的优点是实现简单,线程安全性可靠,且在调用getInstance方法时无需进行额外的同步操作。然而,它的缺点是无论是否真正使用该实例,都会在程序启动时创建实例,可能会导致资源浪费,可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定

懒汉模式

懒汉模式(Lazy Initialization): 在懒汉模式下,单例实例在第一次使用时才被创建,即在调用getInstance方法时进行实例化。这种实现方式需要考虑线程安全性。以下是一种线程安全的懒汉模式的实现

#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;

    Singleton() {} // 私有构造函数

public:
    static Singleton* getInstance() {
        if (instance == nullptr) { // 第一次检查
            std::lock_guard<std::mutex> lock(mtx); // 进入同步区域
            if (instance == nullptr) { // 第二次检查
                instance = new Singleton();
            }
        }
        return instance;
    }

	//防拷贝和赋值
	Singleton(const Singleton&)=delete;
    Singleton& operator=(const Singleton&)=delete;

    // 其他方法...
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

// 使用示例
int main() {
    Singleton* singleton = Singleton::getInstance();
    //...

    return 0;
}


在上述代码中,我们将单例实例定义为一个私有的静态指针成员变量instance。在第一次调用getInstance方法时,会进行线程安全的实例化操作。通过双重检查锁定(double-checked locking)的方式,在加锁前后都对instance进行了检查,以避免多个线程同时创建实例。

懒汉模式的优点是延迟实例化,减少了启动时的资源消耗。然而,它的缺点是需要额外的同步操作,可能会影响性能。另外,在某些编译器下,双重检查锁定的方式并不能保证线程安全,需要使用特定的内存屏障指令来保证正确性。

双重检查锁定是什么? 🤔
双重检查锁定(Double-Checked Locking)是一种常用的懒汉式线程安全单例模式实现方式,它可以避免多个线程同时创建实例,提高了程序的性能和效率。

在双重检查锁定的实现中,首先进行一次instance == nullptr的检查,如果不为空,则直接返回已经创建好的实例;否则进入同步区域,对实例进行初始化。而在同步区域内部还需要再次进行一次instance == nullptr的检查,以确保只有一个线程创建实例。这里的双重检查就是指两次判断instance是否为nullptr。

同步区域(Synchronization Region)是指在多线程编程中需要保证原子性和可见性的一段代码或区域。在同步区域内,只允许一个线程执行代码,其他线程需要等待。

注意 注意 注意 📢

单例模式下,拷贝和赋值函数必须禁掉,那不然就可能会以拷贝构造或赋值的形式诞生多个对象,而不符合单例模式的实例唯一性了。


如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长
【C++】特殊类设计,C++,c++,开发语言,特殊类设计
【C++】特殊类设计,C++,c++,开发语言,特殊类设计文章来源地址https://www.toymoban.com/news/detail-798340.html

到了这里,关于【C++】特殊类设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++进阶(十六)特殊类设计

    📘北尘_ :个人主页 🌎个人专栏 :《Linux操作系统》《经典算法试题 》《C++》 《数据结构与算法》 ☀️走在路上,不忘来时的初心 拷贝只会放生在两个场景中: 拷贝构造函数以及赋值运算符重载 ,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运

    2024年02月19日
    浏览(34)
  • C++语法(26)--- 特殊类设计

    C++语法(25)--- 异常与智能指针_哈里沃克的博客-CSDN博客 https://blog.csdn.net/m0_63488627/article/details/131537799?spm=1001.2014.3001.5501   目录 1.特殊类设计 1.设计一个类,不能被拷贝 C++98 C++11 2.设计一个类,只能在堆上创建对象 1.封掉所有拷贝 C++98 C++11 2.封掉析构函数 3.设计一个类,只能

    2024年02月15日
    浏览(65)
  • 【C++】特殊类的设计

    💕 C++98方式: 在C++11之前,想要一个一个类不被拷贝,只有将 拷贝构造函数 定义为私有,这样在类外就不能调用拷贝构造函数来构造对象了。但是在类内还是可以调用拷贝构造函数来构造对象。 所以正确的做法是 将拷贝构造函数定义为私有,同时拷贝构造函数只声明,不

    2024年02月07日
    浏览(46)
  • c++学习(特殊类设计)[30]

    如果你想要确保对象只能在堆上创建,可以通过将析构函数声明为私有,并提供一个静态成员函数来创建对象。这样,类的实例化只能通过调用静态成员函数来完成,而无法直接在栈上创建对象。 以下是一个示例: 在上面的示例中, HeapOnlyClass 类的构造函数和析构函数都被

    2024年02月14日
    浏览(36)
  • C++特殊类设计&&类型转换

    在普通类的设计基础上,提出一些限制条件设计的类就是特殊类。 拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝, 只需让该类 不能调用拷贝构造函数 以及 赋值运算符重载 即可。  C++98中的方式: 将拷贝构造函数与赋值运算符

    2024年01月16日
    浏览(48)
  • 【C++修炼之路】33.特殊类设计

    每一个不曾起舞的日子都是对生命的辜负 掌握常见特殊类的设计方式 拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。 C++98 将拷贝构造函数与赋值运算符重载只声明不

    2024年02月13日
    浏览(53)
  • C++之特殊类的设计

    目录 一、单例模式 1、设计模式 2、单例模式 1、饿汉模式 2、懒汉模式 3、单例对象的释放问题 二、设计一个不能被拷贝的类 三、设计一个只能在堆上创建对象的类 四、设计一个只能在栈上创建对象的类 五、设计一个不能被继承的类 概念: 设计模式(Design Pattern)是一套被

    2024年02月08日
    浏览(44)
  • C++特殊类设计(单例模式)

    C++98 将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。 原因: 设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义

    2024年01月19日
    浏览(45)
  • 【C++】特殊类设计(单例模式)

    设计模式是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。 使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 根本原因是为了代码复用,增加可维护性。 设计模式的例子:迭代器模式 拷贝一共就只有两个场景,一

    2023年04月22日
    浏览(56)
  • C++特殊类设计及类型转换

    目录 一、特殊类的设计 1.不能被拷贝的类 2.只能在堆区构建对象的类 3.只能在栈区构建对象的类 4.不能被继承的类 二、单例模式 1.饿汉模式 2.懒汉模式 3.线程安全 4.单例的释放 三、C++类型转换 1.C语言的类型转换 2.static_cast 3.reinterpret_cast 4.const_cast 5.dynamic_cast 6.总结 特殊类就

    2024年02月17日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包