- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解c++良好的编程习惯与编程要点由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
假设现在我们要实现一个复数类complex,在类的实现过程中探索良好的编程习惯.
complex.h
# ifndef __COMPLEX__# define __COMPLEX__class complex{ }# endif
防止头文件的内容被多次包含.
# ifndef __COMPLEX__# define __COMPLEX__class complex{ public: double real() const {return re;} double imag() const {return im;} private: doubel re,im;}# endif
例如上面的成员函数:
double real () `const` {return re;}double imag() `const` {return im;}
既然函数不会改变对象,那么就如实说明,编译器能帮你确保函数的const属性,阅读代码的人也明确你的意图。 而且,const对象才可以调用这些函数――const对象不能够调用非const成员函数.
class complex{ public: complex(double r = 0, double i =0) : re(r), im(i) { } private: doubel re,im;}
在初始值列表中,才是初始化。在构造函数体内的,叫做赋值.
为complex 类添加一个+=操作符:
class complex{ public: complex& operator += (const complex &)}
使用引用避免类对象构造与析构的开销,使用const确保参数不会被改变。内置类型的值传递与引用传递效率没有多大差别,甚至值传递效率会更高。例如,传递char类型时,值传递只需传递一个字节;引用实际上是指针实现,需要四个字节(32位机)的传递开销。但是为了一致,不妨统一使用引用.
以引用方式返回函数局部变量会引发程序未定义行为,离开函数作用域局部变量被销毁,引用该变量没有意义。但是我要说的是,如果可以,函数应该返回引用。当然,要返回的变量要有一定限制:该变量的在进入函数前,已经被分配了内存。以此条件来考量,很容易决定是否要返回引用。而在函数被调用时才创建出来的对象,一定不能返回引用.
说回operator +=,其返回值就是引用,原因在于,执行a+=b时,a已经在内存上存在了.
而operator +,其返回值不能是引用,因为a+b的值,在调用operator +的时候才产生.
下面是operator+=与"operator +" 的实现:
inline complex & complex :: operator += (const complex & r){ this -> re+= r->re; this -> im+= r->im; return * this;}inline complex operator + (const complex & x , const complex & y){ return complex ( real (x)+ real (y), //新创建的对象,不能返回引用 imag(x)+ imag(y));}
在operator +=中返回引用还是必要的,这样可以使用连续的操作:
c3 += c2 += c1;
就我们的复数类来说,+可以有多种使用方式:
complex c1(2,1);complex c2;c2 = c1+ c2;c2 = c1 + 5;c2 = 7 + c1;
为了应付怎么多种加法,+需要有如下三种重载:
inline complex operator+ (const complex & x ,const complex & y){ return complex (real(x)+real(y), imag(x+imag(y););}inline complex operator + (const complex & x, double y){ return complex (real(x)+y,imag(x));inline complex operator + (double x,const complex &y){ return complex (x+real(y),imag(y));}
这是某次面试中,面试官大哥告诉我的。想想确实是有道理,类的用户用起来也舒服,一眼就能看见接口.
记得写Big Three 。
C++的类可以分为带指针数据成员与不带指针数据成员两类,complex就属于不带指针成员的类。而这里要说的字符串类String,一般的实现会带有一个char *指针。带指针数据成员的类,需要自己实现class三大件:拷贝构造函数、拷贝赋值函数、析构函数.
class String{ public: String (const char * cstr = 0); String (const String & str); String & operator = (const String & str); ~String(); char * get_c_str() const {return m_data}; private: char * m_data;}
如果没有写拷贝构造函数、赋值构造函数、析构函数,编译器默认会给我们写一套。然而带指针的类不能依赖编译器的默认实现――这涉及到资源的释放、深拷贝与浅拷贝的问题。在实现String类的过程中我们来阐述这些问题.
如果class里有指针,多半是需要进行内存动态分配(例如String),析构函数必须负责在对象生命结束时释放掉动态申请来的内存,否则就造成了内存泄露。局部对象在离开函数作用域时,对象析构函数被自动调用,而使用new动态分配的对象,也需要显式的使用delete来删除对象。而delete实际上会调用对象的析构函数,我们必须在析构函数中完成释放指针m_data所申请的内存。下面是一个构造函数,体现了m_data的动态内存申请:
/*String的构造函数*/inline String ::String (const char *cstr = 0){ if(cstr) { m_data = new char[strlen(cstr)+1]; // 这里,m_data申请了内存 strcpy(m_data,cstr); } else { m_data= new char[1]; *m_data = ""; }}
这个构造函数以C风格字符串为参数,当执行 。
String *p = new String ("hello");
m_data向系统申请了一块内存存放字符串hello:
析构函数必须负责把这段动态申请来的内存释放掉:
inline String ::~String(){ delete[]m_data;}
来看看如果使用编译器为String默认生成的拷贝构造函数与赋值操作符会发生什么事情。默认的复制构造函数或赋值操作符所做的事情是对类的内存进行按位的拷贝,也称为浅拷贝,它们只是把对象内存上的每一个bit复制到另一个对象上去,在String中就只是复制了指针,而不复制指针所指内容。现在有两个String对象:
String a("Hello");String b("World");
a、b在内存上如图所示:
如果此时执行 。
b = a;
浅拷贝体现为:
存储World的内存块没有指针所指向,已经成了一块无法利用内存,从而发生了内存泄露。不止如此,如果此时对象a被删除,使用我们上面所写的析构函数,存储Hello的内存块就被释放调用,此时b.m_data成了一个野指针。来看看我们自己实现的构造函数是如何解决这个问题的,它复制的是指针所指的内存内容,这称为深拷贝 。
/*拷贝赋值函数*/inline String &String ::operator= (const String & str){ if(this == &str) //① return *this; delete[] m_data; //② m_data = new char[strlen(str.m_data)+1]; //③ strcpy(m_data,str.m_data); //④ return *this}
这是拷贝赋值函数的经典实现,要点在于
① 处理自我赋值,如果不存在自我赋值问题,继续下列步骤:
② 释放自身已经申请的内存 。
③ 申请一块大小与目标字符串一样大的内存 。
④ 进行字符串的拷贝 。
对于a = b,②③④过程如下:
同样的,复制构造函数也是一个深拷贝的过程:
inline String ::String(const String & str ){ m_data = new char[ strlen (str) +1]; strcpy(m_data,str.m_data);}
另外,一定要在operator = 中检查是否self assignment假设这时候确实执行了对象的自我赋值,左右pointers指向同一个内存块,前面的步骤②delete掉该内存块造成下面的结果。当企图对rhs的内存进行访问是,结果是未定义的.
想象有一个银行账户的类,每个人都可以开银行账户。存在银行利率这个成员变量,它不应该属于对象,而应该属于银行这个类,由所有的用户来共享。static修饰成员变量时,该成员变量放在程序的全局区中,整个程序运行过程中只有该成员变量的一份副本。而普通的成员变量存在每个对象的内存中,若把银行利率放在每个对象中,是浪费了内存.
static成员函数与普通函数一样,都是只有一份函数的副本,存储在进程的代码段上。不一样的是,static成员函数没有this指针,所以它不能够调用普通的成员变量,只能调用static成员变量。普通成员函数的调用需要通过对象来调用,编译器会把对象取地址,作为this指针的实参传递给成员函数:
obj.func() ---> Class :: fun(&obj);
而static成员函数即可以通过对象来调用,也可以通过类名称来调用.
另一个问题是static成员变量的定义。static成员变量必须在类外部进行定义:
class A{ private: static int a; //①}int A::a = 10; //②
注意①是声明,②才是定义,定义为变量分配了内存.
这些可以用来应付一下面试,在实现单例模式的时候,static成员函数与static成员变量得到了使用,下面是一种称为”饿汉式“的单例模式的实现:
class A{ public: static A& getInstance(); setup(){...}; private: A(); A(const A & rhs); static A a;}
这里把class A的构造函数都设置为私有,不允许用户代码创建对象。要获取对象实例需要通过接口getInstance。”饿汉式“缺点在于无论有没有代码需要a,a都被创建出来。下面是改进的单例模式,称为”懒汉式“:
class A{ public: static A& getInstance(); setup(){....}; private: A(); A(const A& rsh); ...};A& A::getInstance(){ static A a; return a;}
"懒汉式"只有在真正需要a时,调用getInstance才创建出唯一实例。这可以看成一个具有拖延症的单例模式,不到最后关头不干活。很多设计都体现了这种拖延的思想,比如string的写时复制,真正需要的时候才分配内存给string对象管理的字符串.
以上就是详解c++良好的编程习惯与编程要点的详细内容,更多关于c++良好的编程习惯与编程要点的资料请关注我其它相关文章! 。
原文链接:https://www.cnblogs.com/lsgxeva/p/7836297.html 。
最后此篇关于详解c++良好的编程习惯与编程要点的文章就讲到这里了,如果你想了解更多关于详解c++良好的编程习惯与编程要点的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
大家好,我是汤师爷~ 什么是订单履约系统? 订单履约是从消费者下单支付到收到商品的全流程管理过程,包括订单接收、订单派单、库存分配、仓储管理和物流配送等环节,核心目标是确保商品准时、准确地送达消费
大家好,我是汤师爷~ 今天聊聊促销系统整体规划。 各类促销活动的系统流程,可以抽象为3大阶段: B端促销活动管理:商家运营人员在后台系统中配置和管理促销活动,包括设定活动基本信息、使用规则
全称“Java Virtual Machine statistics monitoring tool”(statistics 统计;monitoring 监控;tool 工具) 用于监控虚拟机的各种运
主要是讲下Mongodb的索引的查看、创建、删除、类型说明,还有就是Explain执行计划的解释说明。 可以转载,但请注明出处。  
1>单线程或者单进程 相当于短链接,当accept之后,就开始数据的接收和数据的发送,不接受新的连接,即一个server,一个client 不存在并发。 2>循环服务器和并发服务器
详解 linux中的关机和重启命令 一 shutdown命令 shutdown [选项] 时间 选项: ?
首先,将json串转为一个JObject对象: ? 1
matplotlib官网 matplotlib库默认英文字体 添加黑体(‘SimHei')为绘图字体 代码: plt.rcParams['font.sans-serif']=['SimHei'
在并发编程中,synchronized关键字是常出现的角色。之前我们都称呼synchronized关键字为重量锁,但是在jdk1.6中对synchronized进行了优化,引入了偏向锁、轻量锁。本篇
一般我们的项目中会使用1到2个数据库连接配置,同程艺龙的数据库连接配置被收拢到统一的配置中心,由DBA统一配置和维护,业务方通过某个字符串配置拿到的是Connection对象。  
实例如下: ? 1
1. MemoryCahe NetCore中的缓存和System.Runtime.Caching很相似,但是在功能上做了增强,缓存的key支持object类型;提供了泛型支持;可以读缓存和单个缓存
argument是javascript中函数的一个特殊参数,例如下文,利用argument访问函数参数,判断函数是否执行 复制代码 代码如下: <script
一不小心装了一个Redis服务,开了一个全网的默认端口,一开始以为这台服务器没有公网ip,结果发现之后悔之莫及啊 某天发现cpu load高的出奇,发现一个minerd进程 占了大量cpu,googl
今天写这个是为了 提醒自己 编程过程 不仅要有逻辑 思想 还有要规范 代码 这样可读性 1、PHP 编程规范与编码习惯最主要的有以下几点: 1 文件说明 2 funct
摘要:虚拟机安装时一般都采用最小化安装,默认没有lspci工具。一台测试虚拟网卡性能的虚拟机,需要lspci工具来查看网卡的类型。本文描述了在一个虚拟机中安装lspci工具的具体步骤。 由于要测试
1、修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统
目录 算术运算符 基本四则运算符 增量赋值运算符 自增/自减运算符 关系运算符 逻
如下所示: ? 1
MapperScannerConfigurer之sqlSessionFactory注入方式讲解 首先,Mybatis中的有一段配置非常方便,省去我们去写DaoImpl(Dao层实现类)的时间,这个
我是一名优秀的程序员,十分优秀!