c++类和动态内存分配
2017-11-12 15:26
148 查看
1、类声明
C++中使用关键字 class 来声明类, 其基本形式如下:class 类名
{
public:
//行为或属性
private:
//行为或属性
};
类是一种将抽象转换为用户定义类型的c++工具,它将数据表示和操作数据的方法整合为一个包。在声明部分,c++以数据成员的方式描述数据部分,以成员函数的方式描述共有接口,下面看一个例子:我们要定义一个类型,储存多幅图像的数据(rgb值)以及图像的数量、通道、长宽等信息。
#pragma once #include <vector> #include <memory> #include <iostream> #include <string.h> class Blob { public: Blob(); Blob(int n, int c, int h, int w); ~Blob(); int num; int channels; int height; int width; int data_count; private: std::shared_ptr<float> data; };访问控制:private和public关键字用于访问控制,使用类对象的程序都可以访问共有成员数据和函数,但是只能通过公有成员函数来访问私有成员。这里我们将数据放在共有部分为了方便直接访问,正常出于隐藏数据的主要目标,数据项一般定义在私有部分,而通过成员函数去操作数据。
同时注意到,在声明部分,我们只规定函数接受什么类型的数据,而没有具体的实现。
2、类方法定义
类方法定义主要描述了如何实现类成员函数。定义成员函数时,用作用域解析运算符(::)来标识函数所属的类。#include "Blob.h" Blob::Blob() { data = nullptr; } Blob::Blob(int n, int c, int h, int w) { if (data) data = nullptr; num = n; channels = c; height = h; width = w; data_count = n * c * h * w; data.reset(new float[data_count], std::default_delete<float[]>()); } Blob::~Blob() { }以上,我们就完成了对一个简单类型的定义,调用方法和结构类似。
3、类的构造和析构函数
3.1构造函数
构造函数用于类成员的初始化,其名称都和类名相同。在上面的例子中,Blob();
Blob(int n, int c, int h, int w);
都是构造函数。之前也讲到,出于数据隐藏的目的,数据部分一般放在私有访问中,也就是说我们无法通过直接对变量赋值的方法来初始化一个类,这就用到了构造函数。
我们注意到第一个构造函数没有接受任何参数。这就是默认构造函数,就像是我们用 int i; 去定义一个整数那样,不提供初始值。如果没有提供任何构造函数,将由c++自动提供,不做任何操作。
3.1.1 构造函数使用
两种方法:Blob image(1,2,3,4);Blob image_=Blob(1,2,3,4);
3.2析构函数
用构造函数创建对象后,程序会跟踪对象,直到过期为止。对象过期时,程序将调用析构函数,用于清理工作。例如,如果在构造函数中用new分配了一个内存,则析构函数将使用delete来释放内存。若析构函数不需要进行操作,则编写为空的函数。析构函数的原型:~Blob(); 实现:Blob::~Blob() { }
注意:构造函数不能想普通函数一样调用。若上例中还有一个函数Blob::copy()则可以通过image.copy()来调用,而构造函数则不能。
4、动态内存分配
看下面这个声明和定义:class String { private: char* str; int len; static int str_num; public: String(); String(const char*s); ~String(); };
String::String() { len=4; str=new char[4]; std::strcpy(str,"c++"); str_num++; cout<<str_num<<"objects left"; } String::String(const char* s) { len=std::strlen(s); str=new char[len+1]; std::strcpy(str,s); str_num++; cout<<str_num<<"objects left"; } String::~String() { --str_num; cout<<str_num<<"objects left"; }功能是储存字符串,用一个str_num来计数。这里str_num为静态数据成员,也就是说对于所有成员,只创建一个共享的副本。
其中strcpy()的作用是把字符串复制到新的内存中。
因为在构造函数中使用了new,所以在析构函数中必须调用delete来释放内存。这也是我们下面讨论问题的关键。
String str1("aaa"); String str2("bbb"); String str3("ccc"); pass1(str1); cout<<"str1:"<<str1<<endl; pass2(str2); cout<<"str2:"<<str2<<endl; void pass1(String & rsb) { cout<<" "<<rsb; } void pass2(String sb) { cout<<" "<<sb; }以上是一段调用了上面String定义的代码,其中pass1函数表示参数按引用传递,pass2表示参数按值传递。
这一段的运行结果:pass1的部分,输出正常,而pass2的部分,产生了不可预期的输出。为什么呢?
str2作为函数参数被传递导致了析构函数被调用。虽然值传递可以防止原参数被修改,但是原字符串已被清理,无法识别。这同时也会导致程序退出后计数变量str_num的值为-1,显然是不正确的。这表明析构函数比构造函数多调用了一次,在值传递的时候。
还有一些不正确的使用会导致类似的错误,主要指一些特殊成员函数,我下周再做总结。
参考文献:《c++ prime plus》
相关文章推荐
- C++类和动态内存分配
- C++类和动态内存分配(1)
- c++类和动态内存分配
- C++类和动态内存分配
- c++类接口的实现
- Balon白话MSDN:从普通DLL中导出C++类(1) – dllexport和dllimport的使用方法(中英对照、附注解)
- 通过c++类创建对话框
- 一个操作cvs格式的c++类
- c++类结构记录
- c++类和继承
- c++类的 static 和const那些事
- Cocos2d-x手动绑定C++类到Lua
- Cocos2d-x下Lua调用自定义C++类和函数的最佳实践
- C++类中的static数据成员,static成员函数
- 一维和二维数组 动态内存分配
- C++类模板笔记
- C#调用C++类(以COM组件的形式)
- c++类与对象,数据的共享与保护 小节简单程序实例
- 关于C++类中的土著民:构造函数,复制构造函数,析构函数
- 第十六周oj刷题——Problem A: C++类实现最大数的输出