C++ 之Const
#include "BaseClass.h" #include <iostream> using namespace std; // const只在编译期间保证常量被使用时的不变性,无法保证运行期间的行为 // 程序员直接修改常量会得到一个编译错误,但是使用间接指针修改内存,只要符合语法则不会得到任何错误和警告。 // 因为编译器无法得知你是有意还是无意的修改,但是既然定义成const,那么程序员就不应当修改它,不然直接使用变量定义好了。 // 1、const修饰的量不是常量,仅仅是个只读量。 // 在编译的时候全部替换const变量被赋予的值(这点和C语言的宏相似),在运行的时候该const变量可通过内存进行修改: // 1.1)通过内存(指针)可以修改位于栈区的const变量,语法合乎规定,编译运行不会报错, // 但是在编译的时候所有用到该常量的地方全部被替换成了定义时所赋予的值,然后再运行的时候无法使用通过指针修改后的值。 // 1.2)通过内存(指针)修改位于静态存储区的的const变量,语法上没有报错,编译不会出错,一旦运行就会报告异常。 //注:通过指针修改在全局区上的const变量,编译可通过,运行运行就会报异常。 // const常量书上说一般不分配地址,是指const int global_a = 1; 在函数体外,是全局变量。编译器优化而不分配内存而已,以避免访问内存的低效率。 const int g_Int = 100; void testConst() { BaseClass oBase(100); cout << "========First==========" << endl; BaseClass oBase2 = oBase; cout << "========Second==========" << endl; BaseClass oBase3 = 1000; cout << "========Third==========" << endl; int i =200; oBase.funcConstRefParamter(i); cout << i << endl; cout << "========Fourth==========" << endl; oBase.funcConstParamter(i); cout << i << endl; cout << "========Fifth==========" << endl; // oBase.funcConstRefParamter(g_Int); ////注:通过指针修改在全局区上的const变量,编译可通过,运行运行就会报异常。 // cout << g_Int<< endl; }
#ifndef BASECLASS_H #define BASECLASS_H class BaseClass { public: BaseClass(int nValue); ~BaseClass(); //BaseClass(BaseClass base); // error: copy constructor must pass its first argument by reference 否则存在递归引用的问题 BaseClass(BaseClass &oBase); BaseClass(const BaseClass &oBase);// 这样既能以常量对象(初始化后值不能改变的对象)作为参数,也能以非常量对象作为参数去初始化其他对象 const int getRetConstValue(); // int const getValue(); // 不存在函数名为常量的写法 编译器自动装换成上面的那种函数形式 void funcConstParamter(const int value); void funcConstRefParamter(const int &value); // void funcBodyConst(int a)const; // 修饰的是this指针,不允许修改成员变量的值 int getConstMemberValue() const; // private: public: const int m_nConstMemberValue; // const 成员变量不可以使用赋值的方式来设置值。只能使用初始化列表的方式 int m_value; }; #endif // BASECLASS_H
#include "BaseClass.h" #include <iostream> using namespace std; #define TRACE_LOG(Var) cout << Var<<endl BaseClass::BaseClass(int nValue) : m_nConstMemberValue(nValue) //只能使用初始化列表的方式 { // m_nConstMemberValue = nValue // error const 成员变量不可以使用赋值的方式来设置值。 TRACE_LOG("BaseClass::BaseClass(int nValue)"); // cout << __FUNCTION__ <<endl; } BaseClass::~BaseClass() { } BaseClass::BaseClass(BaseClass &oBase) : m_nConstMemberValue(oBase.getConstMemberValue()) { TRACE_LOG("BaseClass::BaseClass(BaseClass &oBase)"); } BaseClass::BaseClass(const BaseClass &oBase) : m_nConstMemberValue(oBase.getConstMemberValue()) { TRACE_LOG("BaseClass::BaseClass(const BaseClass &oBase)"); } const int BaseClass::getRetConstValue() { int i =100; return i; } void BaseClass::funcConstParamter(const int value) { //int base = const_cast<int>(value); int *base = const_cast<int*>(&value); *base = 520; } void BaseClass::funcConstRefParamter(const int &value) { // int *base = const_cast<int*>(&value); int *base = (int*)(&value); //和上面的语句意思一样 *base = 520; } void BaseClass::funcBodyConst(int a) const { // m_value = a; error: cannot assign to non-static data member within const member function 'funcBodyConst' } int BaseClass::getConstMemberValue() const // const 修饰成员函数一般用作这种成员变量的返回值 { return m_nConstMemberValue; }
BaseClass::BaseClass(int nValue) ========First========== BaseClass::BaseClass(BaseClass &oBase) ========Second========== BaseClass::BaseClass(int nValue) ========Third========== 520 ========Fourth========== 520 ========Fifth==========
按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的.
静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求.
栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存.和我们在数据结构所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。
静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放.