对象的构造与析构(二)
程序员文章站
2022-07-01 23:33:10
[TOC] 1. 析构函数 C++的类中可以定义一个特殊的清理函数,叫做析构函数,语法规则为 析构函数没有参数,也没有返回值类型声明 析构函数在对象销毁时自动被调用 当类中自定义了构造函数,并且构造函数中使用了系统资源(如:堆空间、文件打开,等),则需要自定义析构函数 2. 对象的构造与析构顺序 多 ......
1. 析构函数
- c++的类中可以定义一个特殊的清理函数,叫做析构函数,语法规则为
~classname()
- 析构函数没有参数,也没有返回值类型声明
- 析构函数在对象销毁时自动被调用
- 当类中自定义了构造函数,并且构造函数中使用了系统资源(如:堆空间、文件打开,等),则需要自定义析构函数
2. 对象的构造与析构顺序
多个对象之间
多个对象构造时:
- 栈对象的构造顺序依赖于程序的执行流
- 堆对象的构造顺序依赖于new的使用顺序
- 全局对象的构造顺序是不确定的,不同的编译器可能使用不同的规则
多个对象析构时:
- 栈对象和全局对象的析构顺序与构造顺序相反
- 堆对象的析构发生取决于delete的使用顺序
单个对象内部
单个对象创建时,对象内部构造函数的调用顺序为:
- 先调用父类的构造函数
- 再调用成员变量的构造函数,调用顺序与声明顺序相同
- 最后调用类自身的构造函数
单个对象内部的析构顺序与构造顺序相反。
3. const对象与const成员函数
const对象
- 由const关键字修饰的对象为只读对象
- 只读对象的成员变量不允许被改变
- 只读属性只在编译阶段有效,运行时无效
const成员函数
const成员函数的定义如下所示,需要注意的是,函数声明和函数定义都必须带const关键字。
type classname :: func(type para) const
关于const成员函数的使用,有下面几条规则:
- const对象只能调用const成员函数
- const成员函数只能调用const成员函数
- const成员函数不能直接修改成员变量的值
#include <stdio.h> class test { int mi; public: test(int i); void setmi(int i) const; int getmi() const; void printmi(); }; test::test(int i) { mi = i; } void test::setmi(int i) const { mi = i; //error,const成员函数中不能直接修改成员变量的值 } int test::getmi() const { return mi; } void test::printmi() { printf("printmi(): mi = %d\n", mi); } int main() { const test t1(1); t1.getmi(); //ok,const对象调用const成员函数 t1.printmi(); //error,const对象调用普通成员函数 return 0; }
4. 成员函数、成员变量与对象的关系
从面向对象的角度,对象由属性(成员变量)和方法(成员函数)构成;
从程序运行的角度,对象由数据和函数构成,数据位于栈、堆或全局数据区,函数位于代码段。
- 每一个对象都拥有自己独立的属性(成员变量)
- 所有的对象共享类的方法(成员函数)
- 方法能够直接访问对象的属性
- 方法中的隐藏参数this指针用于值代当前对象
#include <stdio.h> class test { int mi; public: int mj; test(int i); test(const test &t); int getmi(); void print(); }; test::test(int i) { mi = i; } test::test(const test &t) { mi = t.mi; //成员函数可以直接访问对应类对象的成员变量 } int test::getmi() { return mi; } void test::print() { printf("this = %p\n", this); //每个成员函数中隐藏了一个this指针,用于指向当前对象 } int main() { test t1(1); test t2(2); test t3(3); printf("t1.getmi() = %d\n", t1.getmi()); printf("&t1 = %p\n", &t1); t1.print(); printf("t2.getmi() = %d\n", t2.getmi()); printf("&t2 = %p\n", &t2); t2.print(); printf("t3.getmi() = %d\n", t3.getmi()); printf("&t3 = %p\n", &t3); t3.print(); return 0; }
5. 代码实战——数组类intarray
intarray.h
#ifndef _intarray_h_ #define _intarray_h_ class intarray { private: int m_length; int *m_pointer; public: intarray(int len); intarray(const intarray &obj); int length(); bool get(int index, int &value); bool set(int index ,int value); ~intarray(); }; #endif
intarray.cpp
#include "intarray.h" intarray::intarray(int len) { m_pointer = new int[len]; for(int i=0; i<len; i++) { m_pointer[i] = 0; } m_length = len; } intarray::intarray(const intarray &obj) { m_length = obj.m_length; m_pointer = new int[obj.m_length]; for(int i = 0; i < obj.m_length; i++) { m_pointer[i] = obj.m_pointer[i]; } } int intarray::length() { return m_length; } bool intarray::get(int index, int &value) { bool ret = (0 <= index) && (index < length()); if( ret ) { value = m_pointer[index]; } return ret; } bool intarray::set(int index, int value) { bool ret = (0 <= index) && (index < length()); if( ret ) { m_pointer[index] = value; } return ret; } intarray::~intarray() { delete[] m_pointer; }
intarray测试
#include "intarray.h" #include <stdio.h> int main() { intarray a(5); for(int i = 0; i < a.length(); i++) { a.set(i, i + 1); } for(int i = 0; i < a.length(); i++) { int value = 0; if( a.get(i, value) ) { printf("a[%d] = %d\n", i, value); } } intarray b = a; for(int i = 0; i < b.length(); i++) { int value = 0; if( b.get(i, value) ) { printf("b[%d] = %d\n", i, value); } } return 0; }
上一篇: linux系统ffmpeg安装
下一篇: tomcat采坑