第6章 Constant, Static and Name Space

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 member
  set_day(12); // ERROR calls non-const member
  return 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(); // OK
 y(); // Error: ambiguous
 XLib::y(); // OK, resolves to XLib
 z(); // 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 orig
 void 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();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值