C++面向对象编程<七>:堆栈、类模板、函数模板及其他补充
2016-02-22 21:19
573 查看
stack堆、heap栈
stack:所谓栈就是存在于作用域的一块内存空间,如当你调用函数,函数本身就会形成一个stack用来放置它所接受的参数及local object,以及返回地址;heap:指操作系统提供的一块global内存空间,程序可能动态分配空间,并取得,并且要自己释放。
如下
class Complex {...}; ... { Complex c1(1,2); //c1在stack static Complex c2(1,2); Complex* p = new Complex(3); //在heap里 }
c1便是所谓的stack object,其声明在作用域就会结束(上面看来就是离开括号),又叫做auto object;而c2便是所谓的static object,其生命在作用域结束之后还在,直到整个程序结束。
如下为全局
class Complex {...}; ... Complex c3(1,2); int main() { ... }
c3便是global object,其生命在整个程序结束之后才结束。其作用域是整个程序。
看一个正确的写法
class Complex {...}; ... { Complex* p = new Complex; ... delete p; } //p是所谓的heap object,其生命在它被delete后便结束了
看一个错误的写法
class complex {}; ... { complex *p = new complex; } /* 会出现内存泄露,当作用域结束后,p所指的heap object任然存在,但指针p的生命却结束,作用域之外再也看不到p,也就没有机会delete p了 */
new、delete
使用如下
Complex* p = new Complex(1,2); ... delete p;
其中new操作会被转换为下面的步骤
Complex* p; void* mem = operator new (sizeof(Complex) ); //分配内存 p = static_cast<Complex*>(mem); //类型转换 p->Complex::Complex(1,2); //构造函数 /* operator new就是一个函数,主要功能分配空间,而构造函数会转换为 Complex::Complex(p,1,2);p就是this指针 */
其中new的操作步骤示意图如下:
delete的操作会被转换为如下:
Complex::~Complex(p); //析构函数 operator delete(p); //释放内存
再看一个使用如下:
String* p = new String[3]; ... delete[] p; //调用三次析构函数 //delete p; 调用一次析构函数
其中delete的操作步骤示意图如下:
其实new是调用C的malloc函数(分配的空间比申请的空间大),delete函数是调用C的free函数,记住一个new对应一个delete。
类模板、函数模板及其他补充
static关系图如下:
类complex成员函数只有一份(不可能创建了几个对象就有几个函数),但是要处理很多对象,那就得靠this pointer来处理不同的对象。
而static的部分就和对象脱离了,它存在于内存的一部分,只有一份。
什么时候会使用static对象呢?就是和对象无关的部分。
如银行会有很多客户对象,但利率却不会和对象有关(大体部分来说)
staic成员函数和一般成员函数的特征就是static成员函数没有this pointer,既然没有this pointer,那static 成员函数不能和一般的函数一样去访问处理non-static data members,那只能处理static members
下面看一个栗子,如下:
class Account { public: static double m_rate; static void set_rate(const double& x) {m_data = x }; }; double Account::m_rate = 8.0; //静态数据必须要这样定义,因为脱离对象, int main() { Account::set_rate(5.0); Account a; a.set_rate(7.0); }
可以看出调用static函数的两种方式:
1. 通过object调用
2. 通过class name 调用
单例模式
class A { public: static A& getInstance(); setup() {...} private: A(); A(const A& rhs); static A a; ... }; A& A::getInstance() { return a; }
a本来就存在,和对象无关,然后不想其他人创建,那就把构造函数放在private里,那怎么取得a呢,就用个static A& getInstance()取得a,这是与外界的接口。但这不是最好的写法,因为不管你用不用,a都存在。所以更好的写法如下
class A { public: static A& getInstance(); setup() {...} private: A(); A(const A& rhs); ... }; A& A::getInstance() { static A a; //只有当有人掉用这个函数,a才会存在 return a; }
cout
为什么cout能接受不同类型的参数呢?如下图
可以看出cout就是一种ostream,
可以看出cout实际上是重载了<<运算符的函数,用于打印不同类型的数
template
分为两种:class template 和 function template
class template见下程序
template<typename T> class complex { public: complex (T r = 0, T i = 0) : re (r), im(i) {} complex& operator += (const complex&); T real() const {return re; } T imag() const {return im; } private: T re, im; friend complex& _doapl (complex*, const complex&); }; //调用如下 { complex<double> c1(2.5,1.5); complex<int> c2(2,6); }
function template见下程序
class stone { public: stone(int w, int h, int we) : _w(w), _h(h), _weight(we) {} bool operator < (const stone& rhs) const { return _weight < rhs._weight; } private: int _w, _h, _weight; }; template<class T> inline const T& min(const T& a, const T& b) { return b < a ? b : a; } //使用 stone r1(2,3), r2(3,3), r3; r3 = min(r1,r2); //则会调用min函数,函数里面会接着调用stone::operator<函数
namespace
以防写的东西与别人同名。使用方法有两种,见下两种:
using directive:
using namespace std; //把namspace空间的东西全打开 cin >> i; cout << "hello" << endl;
using declaration:
using std::cout; std::cin >> i; cout << "hello" << endl;
相关文章推荐
- Java c++通过des加解密
- OpenJudge百炼习题解答(C++)--题3858:和数
- 程序员面试题精选100题(15)-含有指针成员的类的拷贝[C/C++/C#]
- OpenJudge百炼习题解答(C++)--题4072:判断多个点是否在同一直线
- OpenJudge百炼习题解答(C++)--题4074:积水量
- OpenJudge百炼习题解答(C++)--题4045:与3和5无关的数
- 程序员面试题精选100题(08)-求1+2+...+n[C/C++/C#]
- OpenJudge百炼习题解答(C++)--题4040:买书问题
- Eclipse c/c++编译链接失败解决方法
- OpenJudge百炼习题解答(C++)--题4022:买房子
- OpenJudge百炼习题解答(C++)--题4010:2011
- C/C++列举目录下的文件列表
- OpenJudge百炼习题解答(C++)--题4085:数组去重排序
- 怎么样才算是精通 C++?
- 怎么样才算是精通 C++?
- C++ primer阅读笔记之标准库String类型学习
- c++ vector的用法
- C++11和Boost库
- C++11和Boost库
- c++中换行\n和endl的区别