C++实用技巧分享,控制对象创建

简介: C++实用技巧分享,控制对象创建

Hello,大家好,今天给大家分享两个C++的小技巧。

在通常情况下,我们定义了一个普通的类,然后就可以创建该类的实例对象,但是在某些情况下,允许用户任意的创建对象并不是一个好的方法,这时我们就需要限制用户创建对象。

一般的,对象的创建分两种方式,一种是在栈上创建对象,另一种是在堆上创建对象,下面我们就从这两个方面来讨论如何限制用户操作。

1 只允许用户在堆上创建对象

所谓只允许用户在堆上创建对象,就是只允许用户使用new操作符来创建对象,换句话说要禁止用户在栈上创建对象。

也许你会想,根据类的构造函数和访问限制特点,可以将构造函数声明为私有,但是这样一来,new操作符也不能访问构造函数了。

class X
{
    //...
};
X gObject;//line1
void test()
{
    X lObject;//line2
    X* ptr= new X;//line3
}

针对以上代码,我们希望"line1"和"line2"编译错误,"line3"编译正确,那么我们就需要对类的特殊函数做一些处理。

上面已经说到了,构造函数是不能声明为私有的,否则也会阻止在堆上创建对象,既然这样,构造函数就只能声明为公有了,还有什么方法可以阻止在栈上创建呢。

我们再仔细想一想,在C++中,有这样一条规则:当用户试图在栈上创建对象时,编译器会查找匹配且可以访问的构造函数和析构函数,如果其中一个无法访问,编译就会报错。

这似乎给了我们一点提示,将析构函数声明为私有,这样的话不就可以禁止用户在栈上创建对象了吗。

class X
{
public:
    X(){}
    void Delete()
    {
        delete this;
    }
private:
    ~X(){}
};
X gObject;//line1
void test()
{
    X lObject;//line2
    X* ptr= new X;//line3
}

我们编译一下,发现符合预期。

但是,马上下一个问题来了,如果你使用delete来删除创建出来的对象时,编译器还是报错了。

为此,我们可以再编写一个释放函数,在函数中调用delete操作符,这样所有的问题就都解决了。

下面是示例代码:

class X
{
public:
    X(){}
    void Delete()
    {
        delete this;
    }
private:
    ~X(){}
};
X gObject;//line1
void test()
{
    X lObject;//line2
    X* ptr= new X;//line3
    //...
    ptr->Delete();
}

好了,大功告成,但是,有一点需要注意,我们在成员函数Delete()中,删掉了this指针所指对象,这有点像对象的自杀行为,如果该对象再被引用将会报错,所以请确定不再使用该对象时,再调用删除函数,这个地方一定要注意。

那么我们可以总结:使析构函数私有化,可以禁止在栈上创建对象。

2 只允许在栈上创建对象

这跟我们上一小节刚好相反,我们需要禁止new操作符创建对象,聪明的同学可能已经想到了,那就是将new和delete操作符声明为私有的即可。

class Y
{
public:
    Y(){}
private:
    void* operator new(size_t size);
    void operator delete(void* addr);
};
void test()
{
    Y obj;//line1
    Y* ptr= new Y;//line2
}

编译一下,正如我们所预想的,"line2"将不能通过编译,这就阻止了用户在堆上创建对象,是不是很神奇。

好了,关于今天的分享就到这里了,尽管这样的技巧在平时用的不多,但是在某些场景下的确是很好的处理办法。

例如,如果你正在编写一个同步锁或文件对象等,为了让锁自动打开和释放或者是让文件自动打开和关闭,你就使该类实例只能在栈上创建,在构造和析构函数中编写初始化与释放代码,这样用户创建的类对象就会自动管理资源,从而你也不必担心用户因为忘记释放资源而造成的种种坑了。

再比如有些工厂函数或类方法,不要求用户自行new对象,所以可以加限制,这些技巧并不多用,但在某些场景下还是很好用的,可以让用户更安全的使用类。等遇到实际问题了,可以往这方面想想,有个思路,平时有个印象即可


最后不要忘记点赞哦,您的支持就是对我最大的鼓励^_^

欢迎关注微信公众号-小豆君Qt分享


相关文章
|
7月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
7月前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
6月前
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。
|
6月前
|
存储 编译器 C++
类和对象(上)(C++)
本篇内容主要讲解了C++中类的相关知识,包括类的定义、实例化及this指针的作用。详细说明了类的定义格式、成员函数默认为inline、访问限定符(public、protected、private)的使用规则,以及class与struct的区别。同时分析了类实例化的概念,对象大小的计算规则和内存对齐原则。最后介绍了this指针的工作机制,解释了成员函数如何通过隐含的this指针区分不同对象的数据。这些知识点帮助我们更好地理解C++中类的封装性和对象的实现原理。
|
11月前
|
编译器 C++
C++之类与对象(完结撒花篇)(上)
C++之类与对象(完结撒花篇)(上)
89 0
|
6月前
|
编译器 C++
类和对象(下)C++
本内容主要讲解C++中的初始化列表、类型转换、静态成员、友元、内部类、匿名对象及对象拷贝时的编译器优化。初始化列表用于成员变量定义初始化,尤其对引用、const及无默认构造函数的类类型变量至关重要。类型转换中,`explicit`可禁用隐式转换。静态成员属类而非对象,受访问限定符约束。内部类是独立类,可增强封装性。匿名对象生命周期短,常用于临时场景。编译器会优化对象拷贝以提高效率。最后,鼓励大家通过重复练习提升技能!
|
8月前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
167 19
|
8月前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
203 13
|
7月前
|
安全 编译器 C语言
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。
|
7月前
|
存储 程序员 C语言
【C++篇】深度解析类与对象(上)
在C++中,类和对象是面向对象编程的基础组成部分。通过类,程序员可以对现实世界的实体进行模拟和抽象。类的基本概念包括成员变量、成员函数、访问控制等。本篇博客将介绍C++类与对象的基础知识,为后续学习打下良好的基础。