C++学习11 类和new、delete操作符 类与const关键字
如果你是Java、C#、PHP程序员,那么会对 new 非常熟悉,在这些编程语言中,只能通过 new 来创建对象。
在C++中,你可以像定义变量一样来创建对象,如:
Student stu; //对象已被实例化,已分配内存空间,可以使用了
stu.say(); //调用成员函数
这种情况下,系统会在栈区为对象分配内存。栈区是内存中的一块区域,由系统自动分配和释放,程序员无法操控,一般用来存放函数的参数值、局部变量、局部对象等。
当发生函数调用时,系统将函数参数、局部变量、局部对象依次压入栈区;函数执行结束,再按照先进后出的原则将它们弹出(销毁)。
对于大部分程序,这不会有什么问题。但当你希望在函数调用结束前销毁对象时,你是无能为力的。或者你希望通过 for 循环来创建多个对象,这种方法同样也做不到。
使用 new 创建的对象,可以在任意时刻通过 delete 销毁,而且只需要一个指针指向它。
以前面的 Student 类为例,可以这样来动态创建对象:
new Student;
也可以使用构造函数:
new Student("小明", , 90.5f);
这样,就在堆区为对象分配了内存,并调用了构造函数。
但是此时程序员还无法访问这个对象,因为这个对象既没有名字,也没有指针指向它。这种对象称为匿名对象,它确实存在,但无法访问。
用一个指针来指向Student类的对象:
Student *pStu;
pStu = new Student("小明", , 90.5f);
或者:
Student *pStu = new Student("小明", , 90.5f);
当不再需要对象时,可以通过 delete 销毁:
delete pStu;
这样,就释放掉了对象占用的内存,并调用了析构函数。
需要说明的是:new 在堆区为对象分配内存。与栈区不同的是,堆区内存由程序员分配和释放,系统不会自动销毁,即使函数调用结束了,仍然会保留堆区内存。如果程序员不主动回收堆区内存,那么只能在程序运行结束后由操作系统回收。
为了避免内存泄露,强烈建议 new 和 delete 成对出现,及时销毁不再需要的对象。
例如,下面的代码会造成严重的内存泄露:
#include <iostream>
#include <cstdlib>
using namespace std;
class Demo{
private:
double n;
double m;
int i;
};
void func(){
Demo *p = new Demo;
}
int main(){
int i;
for(i=; i<=; i++){
func();
} system("pause");
return ;
}
当程序运行到 system("pause"); 语句时,你可以打开任务管理器,会发现这个小小的程序竟然占用了 32M 内存。
这是因为每次调用 func 函数,都会创建一个对象,并用 p 指向它。函数运行结束,仅仅释放了指针变量 p 占用的内存,而没有释放 p 所指向的对象占用的内存。
如果在 func 函数中不回收对象内存,那么你将永远无法回收,只能等到程序运行结束由操作系统回收,这就是典型的内存泄露。
另外注意,C语言中的 malloc、free 函数不能用来为对象分配和释放内存。
在类中,如果你不希望某些数据被修改,可以借助 const 关键字加以限定。const 可以用来修饰成员变量、成员函数、对象以及对象的引用。
const成员变量
const 成员变量的用法和普通 const 变量的用法相似,在定义时只需在前面加上 const 关键字即可。const 成员变量的初始化只有唯一的一条途径:参数初始化表。
const成员函数
const 成员函数可以使用类中的所有成员变量,但是不能修改变量的值,这种措施主要还是为了保护数据而设置的。
const 成员函数也称为常成员函数。常成员函数需要在声明和定义的时候在函数头部的结尾加上 const 关键字。请看下面的例子:
class Student{
private:
char *name;
int age;
float score;
public:
char *getName() const;
int getAge() const;
float getScore() const;
};
char *Student::getName() const{
return name;
}
int Student::getAge() const{
return age;
}
float Student::getScore() const{
return score;
}
这段代码,将 getName、getAge、getScore 三个函数定义为常成员函数。需要注意的是,在函数声明和定义的时候都需要加上 const 关键字。
为什么要将这三个个函数定义为常成员函数呢?这三个函数都是为了获取某个成员变量的值,功能单一,并且不希望修改成员变量,如此,定义为常成员函数是非常保险的一种做法,可以避免在这两个函数内部修改成员变量。
const对象
const 也可以用来修饰对象,称为常对象。一旦将对象定义为常对象之后,就只能调用类的常成员函数了。
定义 const 对象的基本语法如下:
const 类名 对象名(实参名);
类名 const 对象名(实参名);
这两种定义方式都是可以的。一旦将对象定义为常对象之后,该对象就只能调用类中的常成员函数了。
常对象举例:
#include <iostream>
using namespace std;
class Student{
private:
char *name;
float score;
public:
Student(char *, float);
char *getName() const;
float getScore() const;
void setName(char *name);
void setScore(float score);
};
Student::Student(char *name, float score){
this->name = name;
this->score = score;
}
char *Student::getName() const{
return name;
}
float Student::getScore() const{
return score;
}
void Student::setName(char *name){
this->name = name;
}
void Student::setScore(float score){
this->score = score;
}
int main(){
const Student stu("小明", 90.5);
stu.getScore();
stu.setScore(); //compile error
return ;
}
本例中,我们将类中的 getName、getScore 函数声明为常成员函数,之后在 main 函数中定义了一个常对象 stu,它只能调用常成员函数,因此在调用 getScore 函数时没有问题,但是在调用setScore 函数时编译报错,因为 setScore 不是常成员函数。
C++学习11 类和new、delete操作符 类与const关键字的更多相关文章
- C++基础学习7:new/delete操作符
在C语言中,动态分配和释放内存的函数是malloc.calloc和free,而在C++语言中,new.new[].delete和delete[]操作符通常会被用来动态地分配内存和释放内存. 需要注意的 ...
- Python学习-11.Python中的类定义
Python是一门面向对象语言,那么作为面向对象的特征——类也是有的.值得注意的是Python中一切皆对象,并不像C#中为了性能考虑,int这些在Python中也是对象.(C#中int是结构体) 如何 ...
- 虚析构函数? vptr? 指针偏移?多态数组? delete 基类指针 内存泄漏?崩溃?
五条基本规则: 1.如果基类已经插入了vptr, 则派生类将继承和重用该vptr.vptr(一般在对象内存模型的顶部)必须随着对象类型的变化而不断地改变它的指向,以保证其值和当前对象的实际类型是一致的 ...
- C++ 重载new和delete操作符
原因: C++标准库提供的new和delete操作符,是一个通用实现,未针对具体对象做具体分析 存在分配器速度慢.小型对象空间浪费严重等问题,不适用于对效率和内存有限制的应用场景 好处: 灵活的内 ...
- [GeekBand] C++学习笔记(1)——以复数类为例
本篇笔记以复数类(不含指针的类)为例进行面向对象的学习 ========================================================= 复数类的声明: class ...
- Javascript的变量与delete操作符
原文:http://charlee.li/javascript-variables-and-delete-operator.html 刚刚看到一篇好文(原文链接), 对Javascript中的dele ...
- C++学习32 重载new和delete运算符
内存管理运算符 new.new[].delete 和 delete[] 也可以进行重载,其重载形式既可以是类的成员函数,也可以是全局函数.一般情况下,内建的内存管理运算符就够用了,只有在需要自己管理内 ...
- javascript之delete操作符
理解delete 理论 代码段的类型 执行上下文 活动对象 / 变量对象 属性的特性 内置属性与 DontDelete 未声明的赋值 Firebug的困惑 在eval中删除变量 浏览器兼容性 Geck ...
- 利用C++11的function和bind简化类创建线程
问题引出 当在类中需要创建线程时,总是因为线程函数需要定义成静态成员函数,但是又需要访问非静态数据成员这种需求,来做若干重复性的繁琐工作.比如我以前就经常定义一个静态成员函数,然后定一个结构体,结构体 ...
随机推荐
- httplib
可爆破目录 import httplib import urllib def sendhttp(): data = urllib.urlencode({'@number': 12524, '@type ...
- hibernate--HQL语法与详细解释
HQL查询: Criteria查询对查询条件进行了面向对象封装,符合编程人员的思维方式,不过HQL(Hibernate Query Lanaguage)查询提供了更加丰富的和灵活的查询特性,因此 Hi ...
- 08-Java 多线程编程
1.Java多线程-线程与进程的区别 (1)线程:程序中单独依靠程序进行运行 线程是程序中的顺序控制流,只能使用分配给程序的资源和环境. (2)进程:执行中的程序 一个进程可以包含一个或多个线程. 一 ...
- EDM营销算法:python自动批量发邮件
EDM营销:全称Email Direct Marketing,即电子邮件营销.企业可以通过使用EDM软件向目标客户发送EDM邮件,建立同目标顾客的沟通渠道,向其直接传达相关信息,用来促进销售.EDM软 ...
- 在Eclipse中使用JUnit4进行单元测试
在Eclipse中使用JUnit4进行单元测试(初级篇) 在Eclipse中使用JUnit4进行单元测试(中级篇) 在Eclipse中使用JUnit4进行单元测试(高级篇)
- GitHub简单使用入门
自从google code关闭了下载服务了之后,GitHub作为了目前最好用的免费开源项目托管站点,众多开源项目都托管在github,其中不乏著名的播放器MPC-HC. 不习惯于英文的朋友,难免少不了 ...
- C#本地时间和GMT(UTC)时间的转换
/// <summary> /// 本地时间转成GMT时间 /// </summary> 4 public static string ToGMTString(DateTime ...
- Python基础(二) —— 字符串、列表、字典等常用操作
一.作用域 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. 二.三元运算 result = 值1 if 条件 else 值2 如果条件为真:result = 值1如果条件为 ...
- datagridview 不显示行号的问题
环境:C#,Winform 场景: 窗体上有两个tab页A.B,每个tab页上都有一个DatagridView.窗体加载后,显示tab A选项卡.序号正常显示,但点击B选项卡后,DatagridVie ...
- 【MySQL】binlog缓存的问题和性能
之前在没有备库的情况下,遇到过more than 'max_binlog_cache_size' bytes of storage 的错误,今天在主备复制的时候又遇到了这个问题 Last_SQL_Er ...