C++ 点滴积累(3)
2011-10-22 21:45
218 查看
1.析构函数的调用时机:
1)} 或 文件尾
2)delete(有条件的)
3)catch()
当中途退出程序时(exit()、abort() )不调用析构函数
2.在函数内部定义的类叫内部类,内部类的成员函数只能是内联函数。
3.静态成员(类属性)
静态数据成员–用关键字static声明;
–该类的所有对象维护着同一份拷贝;
–不能在构造函数中初始化,应在类外单独进行,必须在生成对象之前用(::)来指明所属的类。
静态成员函数
–类外代码可以使用类名和作用域操作符(::)来调用静态成员函数;
–静态成员函数只能引用属于该类的静态数据成员或静态成员函数。
静态成员的性质
静态数据成员
–对象的存储空间中不包含静态成员的位置;
–尽管可能是私有成员,也必须在类外定义和初始化;
–若是对象成员,则必然调用构造函数
静态成员函数
–静态成员函数不含有this 指针;
–静态数据成员或静态成员函数不继承;
–静态成员函数不可以定义为虚函数;
–静态成员函数不必重载也不必为常函数。
5.友元
– 友元是C++提供的一种破坏数据封装和数据隐藏的机制。
– 通过将一个模块声明为另一个模块的友元,一个模块能够使用到另一个模块中本是被隐藏的信息。
– 可以使用友元函数和友元类。
– 友元不是组合,定义和调用时不受类作用域限制。
== 友元函数
友元函数是在类声明中由关键字friend修饰的非成员函数,在它的函数体中能够通过对象名访问private 和protected成员;
友元函数可以是类外的普通函数,也可以是另一类的成员函数,
作用:增加灵活性,使程序员可以在封装和效率间合理选择。
若访问对象的成员,必须前缀对象名。这样可以访问类中的任何访问权限的成员。
== 友元类
若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员(全方位开放)。
声明语法:将友元类名在另一个类中使用friend修饰说明
友元关系是单向的如果B类是A类的友元,则B类的函数可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有、保护数据。(孙悟空钻进铁扇公主肚里。)
友元关系不能传递如果B类是A类的友元,C类是B类的友元,若没特别声明,则C类和A类无友元关系。(朋友的朋友不见得是朋友!)
友元关系不能继承如果B类是A类的友元,B类的子类不会自动成为A类的友元类。(借来的东西不是遗产。)
常引用:被引用的对象不能被更新。const 类型说明符&引用名
常对象:必须进行初始化,且不能被更新。类名const 对象名
常对象只能调用常成员函数;在常函数和非常函数并存时,非常对象只能调用非常函数,在只有常函数时,非常对象可以调用常函数
常成员(包括常数据成员和常函数成员)类型说明符 const 数据成员名 , 返回类型 函数成员名()const
常成员函数
–使用const关键字说明的函数。
–常成员函数不更新对象的数据成员。
–常成员函数说明格式:
类型说明符函数名(参数表)const;
这里,const是函数类型的组成部分,因此在实现部分也要带const关键字。
–const关键字可以被用于参与对重载函数的区分
–派生时可以用const防止基类的函数被子类覆盖;
–const不能用于构造、析构(程序执行不警告)
常对象仅能调用它的常成员函数。
常成员函数的实质:
在常函数:返回类型函数成员名()const 中
const 实质上是用于限定该函数所含的this指针的,即变成了“指向常对象的指针”。于是对象在调用常函数时,尽可放心。
这也回答了为什么只有非静态成员函数(因为静态成员函数不含有this 指针)才能是常函数。
常数据成员
–使用const说明的数据成员。常数据成员/常引用是通过用初始化列表完成赋值的。
100:10:100
0:10:0
常数组:数组元素不能被更新。类型说明符 const 数组名[大小]
指向常量的指针和常指针:
指向常量的指针const int a=99;const int* p = &a;亦可写为:int const * p = &a;
常指针(相当于引用)char * const p = “ABCDE”;
是指针类型的常量;
若声明指针为常量,则指针本身的值不能被改变,即该指针始终指向一个地方,不可改变。常用来作形参接受数组名实参,于是该指针便老老实实地指着该数组不变。这样指针便不可能丢失数组。
指向常量的常指针(很少用)const char *const p = "John";
7.必须使用初始化列表的场合:
(1)类成员是引用;
(2)类含有常数据成员;
(3)被组合的类的构造函数带参,而由组合类创建对象时。
(4)基类的构造函数带参,子类创建对象时
8.“常”与函数的关系
常参数:函数的形参若是指针或引用,就会将实参完全暴露给子函数。若仅仅为了大量传送而非双向传递数据,可用const修饰引用和指针。
const 类型说明符&引用名
const 类型说明符*指针名
常函数:封锁了函数的“写”功能,不能更新数据成员。
常返回:函数返回的是个常量。通常这个常量是指针或引用。
9.改变常对象的数据
一个对象一旦定义为常对象就意味着其所的数据成员都不可更改了,可是在实际应用中会有这种情况:一个存单类,记录了户主、金额、期限等信息,当发生抵押时,户主要变化,其它项不动。
为了适应这种需求,C++提供mutable 关键字,用于修饰常对象中的可变数据成员,使得常函数可以修改它,非常函数也可以用。
mutable 关键字可用于非静态、非常、非引用的数据成员。
10.编译预处理命令
1)#include 包含指令
–将一个源文件嵌入到当前源文件中该点处。
–#include<文件名>
按标准方式搜索,文件位于C++系统目录的include子目录下。
–#include"文件名"
首先在当前目录中搜索,若没有,再按标准方式搜索。
2)#define 宏定义指令
–定义符号常量,很多情况下已被const定义语句取代。
–定义带参数宏,已被内联函数取代。
#undef
–终止由#define定义的宏,使之不再起作用。
3)条件编译指令#if 和#endif
#if常量表达式
//当“常量表达式”非零时编译
程序正文
#endif
4)条件编译指令#else
#if 常量表达式
//当“常量表达式”非零时编译
程序正文1
#else
//当“常量表达式”为零时编译
程序正文2
#endif
5)条件编译指令#ifdef
#ifdef标识符
程序段1
#else
程序段2
#endif
如果“标识符”经#defined定义过,且未经# undef删除,则编译程序段1,否则编译程序段2。
6)条件编译指令#ifndef
#ifndef标识符
程序段1
#else
程序段2
#endif
如果“标识符”未被定义过,则编译程序段1,否则编译程序段2。
7)使用条件编译的头文件
//head.h
#ifndefHEAD_H //避免了重复编译
#define HEAD_H //此标识符被称为“哨兵”
…
class Point
{
…
}
…
#endif
1)} 或 文件尾
2)delete(有条件的)
3)catch()
当中途退出程序时(exit()、abort() )不调用析构函数
2.在函数内部定义的类叫内部类,内部类的成员函数只能是内联函数。
3.静态成员(类属性)
静态数据成员–用关键字static声明;
–该类的所有对象维护着同一份拷贝;
–不能在构造函数中初始化,应在类外单独进行,必须在生成对象之前用(::)来指明所属的类。
静态成员函数
–类外代码可以使用类名和作用域操作符(::)来调用静态成员函数;
–静态成员函数只能引用属于该类的静态数据成员或静态成员函数。
//具有静态数据、函数成员的Point类 #include <iostream> using namespace std; class Point//Point类声明 { public://外部接口 Point(int xx=0, int yy=0) {X=xx;Y=yy;countP++;} Point(Point &p);//拷贝构造函数 int GetX() {return X;} int GetY() {return Y;} static void GetC() {cout<<" Object id="<<countP<<endl;} private://私有数据成员 int X,Y; static int countP; }; Point::Point(Point &p) { X=p.X; Y=p.Y; countP++; } int Point::countP=0; void main()//主函数实现 { Point A(4,5); //声明对象A cout<<"Point A,"<<A.GetX()<<","<<A.GetY(); A.GetC(); //输出对象号,对象名引用 Point B(A); //声明对象B cout<<"Point B,"<<B.GetX()<<","<<B.GetY(); Point::GetC(); //输出对象号,类名引用 }
#include <iostream> using namespace std; class A { public: A(int xx):x(xx){} static void f(A a); private: int x; }; void A::f(A a) { /* 静态成员函数对对象成员的访问是错误的, 因为它是类属性,并不知晓对象的事。 */ //cout<<x; //对x的引用是错误的 cout<<a.x; //正确 } void main() { A obj(2); obj.f(obj); }
静态成员的性质
静态数据成员
–对象的存储空间中不包含静态成员的位置;
–尽管可能是私有成员,也必须在类外定义和初始化;
–若是对象成员,则必然调用构造函数
静态成员函数
–静态成员函数不含有this 指针;
–静态数据成员或静态成员函数不继承;
–静态成员函数不可以定义为虚函数;
–静态成员函数不必重载也不必为常函数。
5.友元
– 友元是C++提供的一种破坏数据封装和数据隐藏的机制。
– 通过将一个模块声明为另一个模块的友元,一个模块能够使用到另一个模块中本是被隐藏的信息。
– 可以使用友元函数和友元类。
– 友元不是组合,定义和调用时不受类作用域限制。
== 友元函数
友元函数是在类声明中由关键字friend修饰的非成员函数,在它的函数体中能够通过对象名访问private 和protected成员;
友元函数可以是类外的普通函数,也可以是另一类的成员函数,
作用:增加灵活性,使程序员可以在封装和效率间合理选择。
若访问对象的成员,必须前缀对象名。这样可以访问类中的任何访问权限的成员。
//使用友元函数计算两点距离 #include <iostream> #include <cmath> using namespace std; class Point//Point类声明 { public://外部接口 Point(int xx=0, int yy=0) {X=xx;Y=yy;} int GetX() {return X;} int GetY() {return Y;} friend double Distance(Point &a, Point &b); private://私有数据成员 int X,Y; }; double Distance( Point& a, Point& b) { double dx=a.X-b.X; double dy=a.Y-b.Y; return sqrt(dx*dx+dy*dy); } int main() { Point p1(3.0, 5.0), p2(4.0, 6.0); double d = Distance(p1, p2); cout<<"The distance is "<<d<<endl; return 0; }
== 友元类
若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员(全方位开放)。
声明语法:将友元类名在另一个类中使用friend修饰说明
友元关系是单向的如果B类是A类的友元,则B类的函数可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有、保护数据。(孙悟空钻进铁扇公主肚里。)
友元关系不能传递如果B类是A类的友元,C类是B类的友元,若没特别声明,则C类和A类无友元关系。(朋友的朋友不见得是朋友!)
友元关系不能继承如果B类是A类的友元,B类的子类不会自动成为A类的友元类。(借来的东西不是遗产。)
#include <iostream> using namespace std; class A { friend class B; public: A(int xx = 1):x(xx){} void Display() {cout<<x<<endl;} private: int x; }; class B { public: void Set(int i); void Display(); private: A a; }; void B::Set(int i) { //访问组合对象的私有成员正是友元的“特长”。 a.x=i; } void B::Display() { a.Display(); } int main() { B obj; obj.Display(); return 0; }6.“常”的种类
常引用:被引用的对象不能被更新。const 类型说明符&引用名
常对象:必须进行初始化,且不能被更新。类名const 对象名
常对象只能调用常成员函数;在常函数和非常函数并存时,非常对象只能调用非常函数,在只有常函数时,非常对象可以调用常函数
常成员(包括常数据成员和常函数成员)类型说明符 const 数据成员名 , 返回类型 函数成员名()const
常成员函数
–使用const关键字说明的函数。
–常成员函数不更新对象的数据成员。
–常成员函数说明格式:
类型说明符函数名(参数表)const;
这里,const是函数类型的组成部分,因此在实现部分也要带const关键字。
–const关键字可以被用于参与对重载函数的区分
–派生时可以用const防止基类的函数被子类覆盖;
–const不能用于构造、析构(程序执行不警告)
常对象仅能调用它的常成员函数。
#include<iostream> using namespace std; class R { public: R(int r1, int r2){R1=r1;R2=r2;} void print(); //const关键字可以被用于参与对重载函数的区分 void print() const; private: int R1,R2; }; void R::print() { cout<<R1<<":"<<R2<<endl; } //const是函数类型的组成部分,因此在实现部分也要带const关键字。 void R::print() const { cout<<R1<<";"<<R2<<endl; } void main() { R a(5,4); a.print(); //调用void print() const R b(20,52); //常对象仅能调用它的常成员函数。 b.print(); //调用void print() const }
常成员函数的实质:
在常函数:返回类型函数成员名()const 中
const 实质上是用于限定该函数所含的this指针的,即变成了“指向常对象的指针”。于是对象在调用常函数时,尽可放心。
这也回答了为什么只有非静态成员函数(因为静态成员函数不含有this 指针)才能是常函数。
常数据成员
–使用const说明的数据成员。常数据成员/常引用是通过用初始化列表完成赋值的。
#include<iostream> using namespace std; class A { public: A(int i); void print(); const int& r; private: const int a; static const int b; //静态常数据成员 }; const int A::b=10; A::A(int i):a(i),r(a) {} void A::print() { cout<<a<<":"<<b<<":"<<r<<endl; } void main() { /* 建立对象a和b,并以100和0作为初值,分别调用构造函数, 通过构造函数的初始化列表给对象的常数据成员赋初值 */ A a1(100),a2(0); a1.print(); a2.print(); }运行结果:
100:10:100
0:10:0
常数组:数组元素不能被更新。类型说明符 const 数组名[大小]
指向常量的指针和常指针:
指向常量的指针const int a=99;const int* p = &a;亦可写为:int const * p = &a;
常指针(相当于引用)char * const p = “ABCDE”;
是指针类型的常量;
若声明指针为常量,则指针本身的值不能被改变,即该指针始终指向一个地方,不可改变。常用来作形参接受数组名实参,于是该指针便老老实实地指着该数组不变。这样指针便不可能丢失数组。
指向常量的常指针(很少用)const char *const p = "John";
7.必须使用初始化列表的场合:
(1)类成员是引用;
(2)类含有常数据成员;
(3)被组合的类的构造函数带参,而由组合类创建对象时。
(4)基类的构造函数带参,子类创建对象时
8.“常”与函数的关系
常参数:函数的形参若是指针或引用,就会将实参完全暴露给子函数。若仅仅为了大量传送而非双向传递数据,可用const修饰引用和指针。
const 类型说明符&引用名
const 类型说明符*指针名
常函数:封锁了函数的“写”功能,不能更新数据成员。
常返回:函数返回的是个常量。通常这个常量是指针或引用。
9.改变常对象的数据
一个对象一旦定义为常对象就意味着其所的数据成员都不可更改了,可是在实际应用中会有这种情况:一个存单类,记录了户主、金额、期限等信息,当发生抵押时,户主要变化,其它项不动。
为了适应这种需求,C++提供mutable 关键字,用于修饰常对象中的可变数据成员,使得常函数可以修改它,非常函数也可以用。
mutable 关键字可用于非静态、非常、非引用的数据成员。
#include <iostream> #include <string> using namespace std; class scrollbar { private: int size; //related to constness mutable string owner; //可变数据成员 public: scrollbar(int sz, string own) : size(sz), owner(own){ } void setSize(int sz) //changes size { size = sz; } void setOwner(string own) const //是竟然可以修改的常函数 { owner = own; } int getSize() const //returns size { return size; } string getOwner() const //returns owner { return owner; } }; void main() { const scrollbar sbar(60, "Window1"); //生成常对象 cout<< sbar.getSize() << ", " << sbar.getOwner() << endl<< endl; // sbar.setSize(100); //can't do this to const obj // 常对象调用常函数,修改mutable数据成员 sbar.setOwner("Window2"); cout<< sbar.getSize() << ", " << sbar.getOwner() << endl<< endl; }
10.编译预处理命令
1)#include 包含指令
–将一个源文件嵌入到当前源文件中该点处。
–#include<文件名>
按标准方式搜索,文件位于C++系统目录的include子目录下。
–#include"文件名"
首先在当前目录中搜索,若没有,再按标准方式搜索。
2)#define 宏定义指令
–定义符号常量,很多情况下已被const定义语句取代。
–定义带参数宏,已被内联函数取代。
#undef
–终止由#define定义的宏,使之不再起作用。
3)条件编译指令#if 和#endif
#if常量表达式
//当“常量表达式”非零时编译
程序正文
#endif
4)条件编译指令#else
#if 常量表达式
//当“常量表达式”非零时编译
程序正文1
#else
//当“常量表达式”为零时编译
程序正文2
#endif
5)条件编译指令#ifdef
#ifdef标识符
程序段1
#else
程序段2
#endif
如果“标识符”经#defined定义过,且未经# undef删除,则编译程序段1,否则编译程序段2。
6)条件编译指令#ifndef
#ifndef标识符
程序段1
#else
程序段2
#endif
如果“标识符”未被定义过,则编译程序段1,否则编译程序段2。
7)使用条件编译的头文件
//head.h
#ifndefHEAD_H //避免了重复编译
#define HEAD_H //此标识符被称为“哨兵”
…
class Point
{
…
}
…
#endif
相关文章推荐
- C++ 点滴积累(5)
- C++ 点滴积累(5)
- C++ 点滴积累(4)
- C和C++的点滴积累(1)
- C++ 点滴积累(2)
- C++点滴积累
- C++ 点滴积累(1)
- C和C++的点滴积累(1)
- C++主题年技巧积累#1——UltraEdit的代码美化
- 数据库知识点滴积累
- Sublime Text3使用点滴积累
- 学习点滴积累之System.Diagnostics.DebuggerStepThrough
- 点滴积累【JS】---JS小功能(checkbox实现全选和全取消)
- C++个人小积累
- C++点滴--lvaue, xvalue, prvalue, glvalue以及rvalue
- 点滴积累【JS】---JS小功能(JS实现隐藏显示侧边栏,也就是分享栏的隐藏显示)
- 点滴积累【JS】---JS小功能(JS实现匀速运动)
- 点滴积累【C#】---抓取页面中想要的数据
- C#点滴积累之番外篇
- OA点滴积累