类的私有private构造函数 ,为什么要这样做
通常我们都将构造函数的声明置于public区段,假如我们将其放入private区段中会发生什么样的后果?没错,我也知道这将会使构造函数成为私有的,这意味着什么?
我们知道,当我们在程序中声明一个对象时,编译器为调用构造函数(如果有的话),而这个调用将通常是外部的,也就是说它不属于class对象本身的调用,假如构造函数是私有的,由于在class外部不允许访问私有成员,所以这将导致编译出错。
你于是说:“哈哈。”我们制造了一个似乎无法产生对象的class.哦,当然,对于class本身,我们还可以利用它的static公有成员,因为它们独立于class对象之外,我们不必产生对象也可以使用它们。嗯,看来我们还是为带有私有构造函数的类找到了一个存在的理由。不过我们不应当满足于此,因为看上去应当还有发掘的余地。
首先我们来认真看一下是不是真的无法创建出一个具有私有构造函数的类对象。“呃,可能未必。”你现在也许会这样说。这很好,让我们再来看看为什么,没错,因为构造函数被class私有化了,所以我们要创建出对象,就必须能够访问到class的私有域;但这一点“我们”是做不到的,那么,谁能做得到呢?class的成员可以做得到;但在我们建构出其对象之前,怎么能利用它的成员呢?噢,刚才我们刚刚提到了static公有成员,它是独立于class对象而存在的,当然,它也是公有的,“我们”可以访问得到。假如在某个static函数中创建了该class的对象,并以引用或者指针的形式将其返回(不可以以值的形式返回,想想为什么),我们就获得了这个对象的使用权。下面是例子:
class WonderfulClass { public: static WonderfulClass* makeAnObject() { // 创建一个WonderfulClass对象并返回其指针 return (new WonderfulClass); } private: WonderfulClass() { } }; int main() ... // delete p; // return 0; |
嗯,这个例子使用了私有构造函数,但它运行得很好:makeAnObject()作为WonderfulClass的静态成员函数,尽心尽责地为我们创建对象:由于要跨函数传递并且不能使用值传递方式,所以我们选择在堆上创建对象,这样即使makeAnObject()退出,对象也不会随之蒸发掉,当然,使用完之后你可不要忘了手工将它清除。
回到前面的思路:除了公有的static成员可以帮助我们访问私有域外,还有没有其它可以利用的“东西”?
噢,你一定想到了使用友元,完全正确。可以使用该类的友元函数或者友元类创建其对象,这里就不举例了。
我们知道没有人会无聊到无缘无故把一个class设为私有,然后再写一个和上面一模一样的makeAnObject()来让它的用户体验一下奇特的感觉。我们也不太相信这只是由于C++的设计原因而导致的一个“顺便的”“特殊的”“无用的”边角功能。它应当是有实际用途的。提醒一下,到了JAVA中你会更容易明白很多静态方法创建对象的原理!!!
嗯,例如,我们想实现这样一个class:它至多只能存在一个,或者指定数量个的对象(还记得标准输入输出流库中那个独一无二的cout吗?),我们可以在class的私有域中添加一个static类型的计数器,它的初值置为0,然后再对makeAnObject()做点手脚:每次调用它时先检查计数器的值是否已经达到对象个数的上限值,如果是则产生错误,否则才new出新的对象,同时将计数器的值增1.最后,为了避免值复制时产生新的对象副本,除了将构造函数置为私有外,复制构造函数也要特别声明并置为私有。
后记:
上面的仁兄评论堪称经典,总结一下就是为了避免创建对象时调用类的构造函数,而是想将生成对象的方式以其它的方式实现,则可将所有的构造函数声明为非public的,这样并不意味着该类无意义,不能实例化生成对象。
生成对象可以两种方式:
1. 通过同时为该类声明Public的static成员函数,在该static成员函数中调用该类私有的构造函数,生成实例,static成员函数是属于任何一个对象,而是属于类的,故可以在没有该类的对象的情况下,通过<类名>::<static 公有成员函数名>(参数)的方式来实现。
2. 调用该类的私有构造函数并生成类对象实例还可以通过该类的友元函数,或该类的友元类的成员函数调用此私有构造函数来实现。
类的私有private构造函数 ,为什么要这样做的更多相关文章
- java利用反射访问类的私有(private)属性及方法
Java语言中,在一个类中,为了不让外界访问到有的属性和方法,通常将其设置为private,用正常的方式(对象名.属性名,对象名.方法名)将无法访问此属性与方法,但有没有其他方法可以访问呢?答案是有的 ...
- C#基础(五)——类中私有构造函数作用
如果类成员有private修饰符,就不允许在类范围以外访问这个类成员.对类构造函数应用private修饰符时,则禁止外部类创建该类的实例.尽管看上去有些不好理解(既然不能实例化,那么这个类还有什么用处 ...
- 1、类、封装(私有private、this关键字)
类与对象 对象在需求中的使用 对面向对象有了了解之后,我们来说说在具体问题中如何使用面向对象去分析问题,和如何使用面向对象. 我们把大象装冰箱为例进行分析. 在针对具体的需求,可以使用名词 ...
- Delphi 跨单元进入(访问)类的私有成员,protected ,private部分
http://blog.sina.com.cn/s/blog_5f8861b60102v1nl.html Delphi 跨单元进入(访问)类的私有成员,protected ,private部分 (20 ...
- 利用反射编写私有 Private 方法的单元测试
利用反射编写私有 Private 方法的单元测试 最近在添加一个新feature时,鉴于要给自己的代码一是增加代码的强壮性,二是增加代码测试的覆盖率.但是遇到了有些方法是 Private 的,但是在调 ...
- CPP_类默认函数:构造函数,拷贝构造函数,赋值函数和析构函数
类默认函数:构造函数,拷贝构造函数,赋值函数和析构函数 // person.h #ifndef _PERSON_H_ #define _PERSON_H_ class Person{ public : ...
- 160803、如何在ES6中管理类的私有数据
如何在ES6中管理类的私有数据?本文为你介绍四种方法: 在类的构造函数作用域中处理私有数据成员 遵照命名约定(例如前置下划线)标记私有属性 将私有数据保存在WeakMap中 使用Symbol作为私有属 ...
- C#私有的构造函数的作用
C#私有的构造函数的作用:当类的构造函数是私有的时候,也已防止C1 c1=new C1();实例化类.常见的应用是工具类和单例模式. using System;using System.Collect ...
- VC6.0中重载操作符函数无法访问类的私有成员
整理日: 2015年03月18日 在 C++ 中,操作符(运算符)可以被重载以改写其实际操作.同时我们可以定义一个函数为类的朋友函数(friend function)以便使得这个函数能够访问类的私有成 ...
随机推荐
- webservice 学习笔记 1
Webservice----------->跨语言服务调用 (视频学习总结) 1-1.有OA系统 需要添加一个功能,登录之后显示天气情况 此时可以使用Webservice eg1: 气象局自己有 ...
- SAP内表查询速度优化实例-OPEN SQL
一.FOR ALL ENTRIES IN 案例 今天碰到工单报工统计分析表查询速度特别慢 经查看源代码: SELECT afpo~dwerk afko~aufnr afpo~matnr AS plnb ...
- bash 中的特殊变量
bash 中的特殊变量 变量 说明 ------------------------------------ $0 当前脚本的文件名 $n 第n个位置参数 $* 传递给脚本或函数的所有参数,$*会将这 ...
- Scrapy框架——安装以及新建scrapy文件
一.安装 conda install Scrapy :之后在按y 表示允许安装相关的依赖库(下载速度慢的话也可以借助镜像源),安装的前提是安装了anaconda作为python , 测试scr ...
- htmlspecialchars_decode 解决掉 &
如果在请求中返回的内容包含 & 请使用htmlspecialchars_decode 搞一下,去掉. 这个纯粹为自己怕到时又找不到这个方法
- python3.6:AttributeError: 'generator' object has no attribute 'next'
环境:PyCharm+Anaconda python版本:3.6 协程测试: #!/usr/bin/env python # -*- coding:utf-8 -*- import time def ...
- ubunut 1804 sublime text3
—– BEGIN LICENSE —– TwitterInc User License EA7E- 1D77F72E 390CDD93 4DCBA022 FAF60790 61AA12C0 A3708 ...
- Linux安装配置nfs实现共享远程目录
1. 服务端安装nfs yum -y install nfs-utils rpcbind 2.编辑/etc/exports /etc/exports文件内容格式: <输出目录> [客户端1 ...
- vue项目在webpack打包后背景图片显示不了
加上 publicPath:'../../'即可
- ARM-LINUX学习记录
1:调用C语言函数之前会有一段汇编代码在前面执行来完成软硬件方面的初始化.比如:关闭看门狗:初始化时钟:设置堆栈:调用main函数等.在学习51单片机时候这些操作是由开发环境(如KEIL)在编译C代码 ...