静态对象
全局变量、本地变量
static: 持久存储(在哪里)
访问受局限(谁能看到你)
static本地变量就是全局变量
全局变量static: 只在这个.c文件里有效
本地变量static: 这个本地变量具有持久存储, 无论是否离开,本地变量都是保存着这个值的.(其实static本地变量就是全局变量)
函数static: 这个函数只能在.c文件里被访问,.c以外是无法访问的.
这里写图片描述
说明:(1). File1: global是一个全局变量,
在File2: 可以直接用extern来使用g_global
(2). File1: static int s_local, 表明s_local只能在File1文件
中使用, 就算在File2中使用static, 也只能骗过编译器,
但骗不过linker.
为何骗不过linker: s_local只能在File1中使用, File2中
extern int s_local要使用File1中的s_local, 两者相矛
盾,所以链接失败.
(3). static void hidden() 只能在File1文件中使用, 不能在File2文件中使用.
全局变量的初始化
X global_x(12,34);
main不是第一个被调用的,先调ctor
程序结束时,析构被执行
类的成员是static
C语言有两种persistent的东西:全局变量(包括静态的本地变量)/malloc出来的东西, 即离开了函数还在的东西
不随着对象不同而不同:persistent,借助static来做
static member:hidden+persistent,是整个类的东西
静态成员变量:在类的所有对象中都一样,且值保持一致
//extern int i; 不知道位置
class A {
public:
A() { i = 0; }
void print() { cout << i << endl; }
void set(int ii) { i = ii; }
private:
static int i; //无法编译,这个静态的本地变量在全局,但是这是声明,并没有这个i的位置,写在class里的所有东西都是声明,需加上下面一句
};
int A::i; //需写在cpp里,一定需要对应的cpp文件,否则无处安身 *
int main() {
A a, b;
a.set(10);
b.print();
return 0;
}
inline的body可以放在.h文件中,不需要.cpp文件
*改成static int A:: i; 报错,它意味着只有这个cpp文件可以访问,但是类的静态成员可能在外部被访问,int A::i(20);是可以的
类里面说A():i(20){} 是错误的,因为A的i是一个静态成员,只能在自己定义的地方被初始化,不能在初始化列表里
void set(int i){this->i = i;} 是正确的
如果静态成员变量是public的,main中可以用cout<<a.i<<endl;
也可以用cout<<A::i<<endl;
静态成员函数:
对于C++来说,所有的函数本来就是全局的,函数不跟着对象走
public:
static void say(int ii) { cout << i << endl; }
main:
a.say(0);
A::say(0);//ok
加上private:
int k;
然后say去访问k是不行的,静态的函数只能够访问静态的成员变量
同样say{cout<i}是不行的,this只能用于访问非静态函数,静态函数与对象的存在与否无关
运算符重载基本规则
写函数改变运算符的行为
运算符重载细则
不能自己创造运算符来重载,**
只能对一个类和枚举的类型来做
重载的运算符保持原有的操作数个数,保持优先级
就是把运算符的运算用自己写的函数来表达
重载乘号:operator *()
它可以做成员函数
const String String: :operator +(const String& that);
也可以做全局函数
const Striing operator+ (const String& r,const String& l);
作为成员函数,this是第一个参数
class Integer
{
public:
Integer(int n = 0):i(n) {}
const Integer operator+(const Integer& n) const
{
return Integer(i+n.i); //不修改加数的值,会生成一个新的类,然后返回这个类的对象
}
……
private:
int i;
};
函数前面必须是const,否则可以做左值,例如a+b=6
Interger x(1),y(5),z; x + y ===>x.operator+(y) //operator+看作一个函数整体,接受y传入
运算符左边那个算子叫receiver,决定用哪个加
如果编译器看到inline,然后某个对象没有被使用,仅仅是为了传参数,会直接优化,没有拷贝构造
z=x+3;会用构造函数把3构造成一个对象
z=3+y;需要类把自己的对象变成一个int型,编译无法通过
z=x+3.5 不行,double到int不能自动转换,除非类里面就是double,但是int可以自动转换为double
一元参数,例如对自己取负,实质上是制造出一个新的对象
const Integer operator-() const { return Integer(-i); }
作为全局函数,需要把两个算子都写进去
const Integer operator+(
const Integer& rhs,
const Integer& 1hs);
Integer x,y;
x + y ===> operator+(x,y);
此时在两个参数上都可以做类型转换
class Integer
{
friend const Integer operator+ (
const Integer& lhs,
const Integer& rhs);
……
};
const Integer operator+ (
const Integer& lhs,
const Integer& rhs)
{
return Integer(lhs.i + rhs.i);
}
作为全局函数时,z=3+y
是可以的,把3变成那个类的对象
而 z=3+7
同样可以,把结果10直接构造成类的值
到底是选择成员对象还是非成员
tips:
一元的应该做成成员的
而= () [] -> ->*必须是成员的
赋值操作符应该是
其他二元的等全部做成非成员的
运算符重载-原型
函数的原型是怎样的,怎么传入传出
赋值的,参数是整数怎么做
传进去的参数肯定是引用,看运算符会不会修改算子
++,–,+=,-=会修改算子,不能用const
返回值看是对自己做修改还是创造了一个新的对象,以及返回的可以不可以做左值,加法就必须做const,赋值是修改自己,函数后面不能有const,但是返回后也应该可以修改,所以返回一个reference,并且后续也可以做左值
index:参数是整数 a[6],可以做左值,返回reference
大于小于返回布尔量
+-*/%^&|~
—const T operatorX(const T& I, const T& r) const;
! && || < <= == >= >
—bool operatorX(const T& I, const T& r) const;
[]
—T& T::operator[](int index);
class Integer
{
public:
…
const Integer& operator++(); //prefix++
const Integer operator++(int); //postfix++
const Integer& operator--(); //prefix--
const Integer operator++(int); //postfix--
};
加加在前面的没有参数,返回一个引用,++a返回a加了之后的结果,就是当时的那个a,返回引用就可以,但是都是const,禁止做左值,a++=6
加加在后面返回一个新对象,返回加以前的结果,但是返回的已经不是以前的那个a了,
int不会起作用,只是让编译器区分
const Integer& Integer::operator++(){
*this += 1;
return *this; //this是指针,加个星之后变成对象,且保证不会被修改
const Integer Integer::operator++(int){
Integer old(*this);//拷贝构造,用一个对象制造一个新的对象
++(*this);//用第一个定义第二个
return old; //不能return reference,因为是本地变量的reference,离开函数后reference就不存在,所以需要返回一个新的对象
}
++x;//calls x.operator++()
x++;//calls x.operator++(0)//这两个是重载函数
class Integer{
public:
..
bool operator==(const Integer& rhs) const;
bool operator!=(const Integer& rhs) const;
bool operator<(const Integer& rhs) const;
bool operator>(const Integer& rhs) const;
bool operator<=(const Integer& rhs) const;
bool operator>=(const Integer& rhs) const;
};
bool Integer::operator==(const Integer& rhs) const{
return i == rhs.i;
}
bool Integer::operator!=(const Integer& rhs) const{
return !(*this == rhs.i);
}
bool Integer::operator<(const Integer& rhs) const{
return i < rhs.i;
}
bool Integer::operator>(const Integer& rhs) const{
return rhs<*this;
}
bool Integer::operator<=(const Integer& rhs) const{
return !(rhs<*this);
}
bool Integer::operator>=(const Integer& rhs) const{
return !(*this<rhs);
}
只定义了两个原函数,等于和小于,只有这两个深入到this和rhs里面的i
所有上面函数都做成inline,不担心性能损失
[]: index
只用作成员的,用于类表达一种容器的概念
Vector v(100);
v[10]=45; 返回成员类型的引用,可以做左值
class Vector {
public:
Vector(int size) :m_size(size) {
m_array = new int[size];
}
~Vector() { delete m_array; }
int& operator[](int index) { return m_array[index]; }
private:
int m_size;
int *m_array; //可以扩展
};