第6章 Constant, Static and Name Space

news/2024/10/19 17:41:38/

Const

• declares a variable to have a constant value

const int x = 123; 

x = 27; // illegal! 

x++; // illegal! 

int y = x; // Ok, copy const to non-const 

y = x; // Ok, same thing 

const int z = y; // ok, const is safer

变量variable

常量 constant ,值不会发生变化的变量,如被const修饰的x

字面量 literal ,如整数123

Constants

• Constants are variables

– Observe scoping rules

– Declared with “const” type modifier

• A const in C++ defaults to internal linkage

– the compiler tries to avoid creating storage for a const --  holds the value in its symbol table.

– extern forces storage to be allocated

Compile time constants

const int bufsize = 1024; 

• value must be initialized 

• unless you make an explicit extern declaration:

extern const int bufsize; 

• Compiler won't let you change it

• Compile time constants are entries in compiler symbol  table, not really variables.

Run-time constants

• const value can be exploited

const int class_size = 12;  编译时常量

int finalGrade[class_size]; // ok 

int x; 

cin >> x; 

const int size = x; 

double classAverage[size]; // error! c++98是错的,不能用变量作为数组大小,c++11才对

Aggregates

• It’s possible to use const for aggregates, but storage will  be allocated. In these situations, const means “a piece of  storage that cannot be changed.

• However, the value  cannot be used at compile time because the compiler is  not required to know the contents of the storage at compile  time. 

const int i[] = { 1, 2, 3, 4 };  数组元素不能修改

float f[i[3]]; // Illegal  c++98标准,const变量不能做其他数组大小

struct S { int i, j; }; 

const S s[] = { { 1, 2 }, { 3, 4 } }; 

double d[s[1].j]; // Illegal

Pointers and const

• char * const q = "abc"; //     q is const 

*q = 'c'; // OK 

q++; // ERROR 

• const char *p = "ABCD";  // (*p) is a const char 

*p = 'b'; // ERROR! (*p) is the const

Quiz: What do these mean?

string p1( “Fred" ); 

const string* p = &p1;  //对象不能改

string const* p = &p1;  //对象不能改

string *const p = &p1; //指针不能改

const在*之前说明对象不能不能改,在*后面表示指针不能改

Pointers and constants

Remember:

 *ip = 54; // always legal since ip points to int

 *cip = 54; // never legal since cip points to const int

ip = &ci错误,因为ci可能被*ip修改

cip = &ci正确,是因为cip指针不能修改对象,所以ci不会被修改,安全

String Literals

char* s = "Hello, world!";

• s is a pointer initialized to point to a string constant

• This is actually a const char* s but compiler accepts it  without the const

• Don't try and change the character values (it is undefined  behavior)

• If you want to change the string, put it in an array:

char s[] = "Hello, world!";

int main(){char* s = "abc";char a[] = "abc";printf("s=%p\n", s);printf("a=%p\n", a);
}
/*
输出:
s=0x103f41f9e  地址比a小
a=0x7ff7bbfc1334
a在栈内,s指向的内存在很小的地方
*/
int main(){char* s = "abc";char a[] = "abc";printf("s=%p\n", s);printf("a=%p\n", a);s[0] = 'c';pringf("1\n");a[0] = 'c';printf("2\n");
}
/*
s[0] = 'c'报错
*/

Conversions

• Can always treat a non-const value as const

void f(const int* x);

int a = 15; 

f(&a); // ok

const int b = a; 

f(&b); // ok

b = a + 1; // Error!

You cannot treat a constant object as non-constant without an explicit cast 

(const_cast)

Passing by const value?

void f1(const int i) {

i++; // Illegal -- compile-time error 

}

Returning by const value?

int f3() { return 1; } 

const int f4() { return 1; } 

int main() { 

const int j = f3(); // Works fine 

int k = f4(); // But this works fine too! 

}

Passing and returning addresses 

• Passing a whole object may cost you a lot. It is better  to pass by a pointer. But it’s possible for the 

programmer to take it and modify the original value. 

• In fact, whenever you’re passing an address into a  function, you should make it a const if at all possible. 

• Example: ConstPointer.cpp, ConstReturning.cpp

const object

Constant objects

• What if an object is const?

const Currency the_raise(42, 38);对象里的任何一个成员变量都不能被修改

• What members can access the internals?

• How can the object be protected from change? 

• Solution: declare member functions const

– Programmer declares member functions to be safe

Const member functions

• Cannot modify their objects

//不保证不修改,不是保证修改
int Date::set_day(int d){//...error check d here...day = d; // ok, non-const so can modify
}
//保证不修改成员变量,不会调用非const的成员函数
//因为调用了非const成员函数可能会修改成员变量
int Date::get_day() const { day++; //ERROR modifies data memberset_day(12); // ERROR calls non-const memberreturn day; // ok}

Const member function 

• Repeat the const keyword in the definition as well as 

the declaration 声明和定义都要标注const

int get_day () const;

int get_day() const { return day };

• Function members that do not modify data should be 

declared const

• const member functions are safe for const objects

Const objects

• Const and non-const objects

// non-const object
Date when(1,1,2001); // not a const
int day = when.get_day(); // OK
when.set_day(13); // OK
// const object
const Date birthday(12,25,1994); // const
int day = birthday.get_day(); // OK
birthday.set_day(14); // ERROR
class A{int i = 0;
public:A(int li):i(li){}
int getV() const{return i;}
void setV(int v){i = v;}
};int main(){A a(10);const A aa(11);a.setV(12);cout << aa.getV() << endl;aa.setV(13);//报错,不能修改成员变量
}
class A{int i = 0;
public:A(int li):i(li){}int f() const{cout << "f() const" << endl;reutrn i;}int f() const{cout << "f()" << endl;return i;}void setV(int v){i = v;}
};int main(){A a(10);const A aa(11);a.setV(12);a.f();//调用无const的f()aa.f();//调用有const的f()
}
//两个函数构成重载
//int f() const相当于int f(const A* this) const
//int f() 相当于int f(A* this)
//const函数指的是this是const

Constant in class

class A {const int i;
};

• has to be initialized in initializer list of the constructor

//当i是const时
//不能用构造函数赋值
A(int x){i = x;
}
//可以用初始化列表的方式给i设置初始化值
A(int x): i(x){}

Compile-time constants in  classes

class HasArray {const int size;int array[size]; // ERROR!
};
//• use "anonymous enum" hack 匿名枚举基础
class HasArray {enum { size = 100 };int array[size]; // OK!
};
//• Make the const value static:
class HasArray{static const int size = 100;//static指所有对象使用同一个变量int array[size];
}
//·static indicates only one per class(not one per obeject)

Static

Static in C++

Two basic meanings

• Static storage

–allocated once at a fixed address

• Visibility of a name

• internal linkage

  • Don't use static except inside functions and 

classes.

  • 静态本地变量实际上是特殊的全局变量

  • 它们位于相同的内存区域

  • 静态本地变量具有全局的生存期,函数内的局部作用域

Uses of “static” in C++

Global static hidden in file

C语言规则,File 2编译通过,但链接时extern int s_local报错,因为在File1中属于static,只能在当前文件使用

Static inside functions 

• Value is remembered for entire program

• Initialization occurs only once

• Example: 

–count the number of times the function has been called

void f() {static int num_calls = 0;...num_calls++;
}

Static applied to objects

• Suppose you have a class 

class X {X(int, int);~X();...
};

• And a function with a static X object

void f() {static X my_X(10, 20);...
}
class A{
private:int i;
public:A(int li):i(li){cout << "A()" << i << endl;}~A(){cout << "~A()" << i << endl; }
};
A a(10);
int main(){cout << "main()" << endl;cout << "end of main()" << endl;
}
/*
输出:
A()10
main()
end of main()
~A()10
全局变量在main之前创建,main之后销毁
*/
class A{
private:int i;
public:A(int li):i(li){cout << "A()" << i << endl;}~A(){cout << "~A()" << i << endl; }
};
A a(10);void f(){A aa(11);
}
int main(){cout << "main()" << endl;f();cout << "end of main()" << endl;
}
/*
输出:
A()10
main()
A()11
~A()11
end of main()
~A()10
*/

如果f()是static

class A{
private:int i;
public:A(int li):i(li){cout << "A()" << i << endl;}~A(){cout << "~A()" << i << endl; }
};
A a(10);void f(){static A aa(11);
}
int main(){cout << "main()" << endl;f();cout << "-----" << endl;f();cout << "end of main()" << endl;
}
/*
输出:
A()10
main()
A()11
--------
end of main()
~A()11
~A()10
第一次调用f()时才构造aa,aa的析构发生在main函数结束,并且第二次调用函数时不会再构造aa
*/

Static applied to objects ...

• Construction occurs when definition is  encountered

–Constructor called at-most once

–The constructor arguments must be satisfied

• Destruction takes place on exit from program

–Compiler assures LIFO order of destructors

Conditional construction

• Example: conditional construction

void f(int x) {if (x > 10) {static X my_X(x, x * 21);...
}

•my_X

–is constructed once, if f() is ever called with x > 10

–retains its value

–destroyed only if constructed

Global objects

• Consider 

#include "X.h"
X global_x(12, 34);
X global_x2(8, 16);

• Constructors are called before main() is entered

–Order controlled by appearance in file

– In this case, global_x before global_x2

– main() is no longer the first function called

• Destructors called when 

–main() exits

–exit() is called

Static Initialization Dependency

• Order of construction within a file is known

• Order between files is unspecified!

• Problem when non-local static objects in different files 

have dependencies.

• A non-local static object is:

–defined at global or namespace scope

–declared static in a class

–defined static at file scope

x2的构造需要x1,但两个在不同的文件,跨编译单元无法保证构造顺序

Static Initialization Solutions

• Just say no -- avoid non-local static  dependencies.

• Put static object definitions in a single file in correct order.

Can we apply static to members?

• Static means 

–Hidden

–Persistent

• Hidden: A static member is a member

–Obeys usual access rules

• Persistent: Independent of instances

• Static members are class-wide 

–variables or 

–functions

class A{
private:int i;static int s;
public:A(int li):i(li){s = 0;cout << "A()" << i << endl;}~A(){cout << "~A()" << i << endl; }void setS(int k){s = k;}int getS() const{return s;}};int A::s = 0;//需要写这个定义,因为静态成员变量相当于全局变量,不写出现链接错误,但是定义前面不能写static,因为要在其他的文件使用A类。
int main(){A a1(10);A a1(20);cout << a2,getS() << endl;a1.setS(11);cout << a2,getS() << endl;
}
/*
输出:
A()10
A()20
0
11 //a2打印s是11。说明静态成员变量在所有对象中共享,实际上是因为静态成员变量属于特殊的全局变量
~A()20
~A()10
*/

静态成员变量在.h的类中声明,一定要注意在.cpp中写定义

Static members

• Static member variables

–Global to all class member functions

–Initialized once, at file scope

–provide a place for this variable and init it in .cpp

–No ‘static’ in .cpp

• Example: StatMem.h, StatMem.cpp

• Static member functions

–Have no implicit receiver ("this") 

• (why?)

–Can access only static member variables 

• (or other globals)

–No ‘static’ in .cpp

–Can’t be dynamically overridden

• Example: StatFun.h, StatFun.cpp

To use static members

• <class name>::<static member>

• <object variable>.<static member>

NameSpace

Controlling names:

• Controlling names through scoping

• We’ve done this kind of name control:

class Marbles {enum Colors { Blue, Red, Green };...
};
class Candy {enum Colors { Blue, Red, Green };...
};

Avoiding name clashes

• Including duplicate names at global scope is a problem:

// old1.h
void f();
void g();
// old2.h
void f();
void g();

Avoiding name clashes (cont)

• Wrap declarations in namespaces.

// old1.h
namespace old1 {void f();void g();
}
// old2.h
namespace old2 {void f();void g();
}

Namespace

• Expresses a logical grouping of classes,  functions, variables, etc.

• A namespace is a scope just like a class

• Preferred when only name encapsulation is 

needed

namespace Math {double abs(double );double sqrt(double );int trunc(double);...
} // Note: No terminating end colon!

Defining namespaces

• Place namespaces in include files:

// Mylib.h
namespace MyLib {void foo();class Cat {public:void Meow();};
}

Defining namespace functions

• Use normal scoping to implement functions in 

namespaces.

// MyLib.cpp
#include ”MyLib.h”
void MyLib::foo() { cout << "foo\n"; }
void MyLib::Cat::Meow() { cout << "meow\n"; }

Using names from a namespace

• Use scope resolution to qualify names from a namespace.

• Can be tedious and distracting.


#include ”MyLib.h”
void main(){MyLib::foo();MyLib::Cat c;c.Meow();
}

Using-Declarations

• Introduces a local synonym for name

• States in one place where a name comes 

from.

• Eliminates redundant scope qualification:

void main() {using MyLib::foo;using MyLib::Cat;foo();Cat c;c.Meow();
}

Using-Directives

• Makes all names from a namespace available.

• Can be used as a notational convenience.

void main() {using namespace std;using namespace MyLib;foo();Cat c;c.Meow();cout << “hello” << endl;
}

Ambiguities

• Using-directives may create potential ambiguities.

• Consider:

// Mylib.h
namespace XLib {void x();void y();
}
namespace YLib {void y();void z();
}

Ambiguities (cont)

• Using-directives only make the names 

available.

• Ambiguities arise only when you make calls.

• Use scope resolution to resolve.

void main() {using namespace XLib;using namespace YLib;x(); // OKy(); // Error: ambiguousXLib::y(); // OK, resolves to XLibz(); // OK
}

Namespace aliases

• Namespace names that are too short may clash

• names that are too long are hard to work with

• Use aliasing to create workable names

• Aliasing can be used to version libraries.

namespace supercalifragilistic {void f();
}
namespace short = supercalifragilistic;
short::f();

Namespace composition

• Compose new namespaces using names from other 

ones.

• Using-declarations can resolve potential clashes.

• Explicitly defined functions take precedence.

namespace first {void x();void y();
}
namespace second {void y();void z();
}namespace mine {using namespace first;using namespace second;using first::y(); // resolve clashes to first::x()void mystuff();...
}

Namespace selection

• Compose namespaces by selecting a few 

features from other namespaces.

• Choose only the names you want rather than 

all.

• Changes to “orig” declaration become 

reflected in “mine”.

namespace mine {using orig::Cat; // use Cat class from origvoid x();void y();
}

Namespaces are open

• Multiple namespace declarations add to the 

same namespace.

–Namespace can be distributed across multiple files. 

//header1.h
namespace X {void f();
}
// header2.h
namespace X {void g(); // X how has f() and g();
}


http://www.ppmy.cn/news/96687.html

相关文章

【JDK】一、jdk17的下载与安装配置(图文说明超详细)

JDK17的下载与安装 前言一、JDK17下载1、官方下载地址 &#xff08; Oracle中国的官方网站&#xff09; 二、JDK17安装1、先看一下我现在的java版本和环境变量2、开始新的安装第一步&#xff1a;双击下载的jdk-17.0.7_windows-x64_bin.exe 进入到安装页面第二步&#xff1a;jdk…

定制底部footer bug:切换tab时position fixed会抖动

文章目录 bug描述position:fixed是啥&#xff1f;有啥用为什么切换tab的时候会抖动如何解决自定义一个InBody组件&#xff0c;将里面所有的元素放到body里面需要放到的底部的内容都放到这个组件里面 bug描述 在element admin里面定制了footer组件&#xff0c;每个页面也可还有…

剑指 Offer 10- II 青蛙跳台阶问题

题目&#xff1a; 一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。 答案需要取模 1e97&#xff08;1000000007&#xff09;&#xff0c;如计算初始结果为&#xff1a;1000000008&#xff0c;请返回 1。 示例 1&am…

URL中特殊字符处理

在实际开发中&#xff0c;难免遇到url的出现一些特殊字符&#xff0c;此时需要编码处理&#xff0c;平时在浏览直接输入 ascii 表以外的字符时&#xff0c;浏览器会自动帮我们编码&#xff0c;但是在开发中&#xff0c;需要我们手动编码。 带有功能的特殊符号 加号 &#xff…

有感(1)

今晚喝了酒&#xff0c;看着平凡的世界感觉很有深度&#xff0c;感慨于1976年的长辈们为了改变命运而学习&#xff0c;感觉超越了目前我的精神状态太多&#xff0c;可惜去年才意识到这个问题&#xff0c;我是悲哀的一个&#xff0c;也是懦弱的一个&#xff0c;无法在众多问题中…

dom中的事件处理

事件参考 | MDN (mozilla.org) 什么是事件 事件监听方式 直接在html中编写JavaScript代码(了解) <button οnclick"console.log(按钮1发生了点击~);">按钮1</button> DOM属性&#xff0c;通过元素的on.....来监听事件 // 2.onclick属性// function h…

android 12.0Launcher3长按拖拽时最后一屏未满时不让拖拽到后一屏(二)

1.概述 在12.0定制化开发中,如果专门适配老年机的时候,这时客户提出要求,如果最后一屏未满时,不让拖拽到后面一屏的空屏中,等当前屏填满了以后,才能拖到下一屏的功能,所以要从workspace的拖拽类开始着手分析 2.长按拖拽时最后一屏未满时不让拖拽到后一屏(二)核心类 pa…

第2章 Class

Point结构体 //C语言写法 typedef struct point{float x;float y; }Point;Point a; a.x 1; a.y 2; //const表示p指向的对象里的值不能由p指针修改 void print(const Point* p){printf("%d %d\n", p -> x, p -> y); } print(&a);//想实现点的移动&#x…