首页 服务器 编程 必备知识 搜索引擎 圩日手册
站内搜索
最近浏览
推荐文章
热文排行

『21天精通C++』第二周学习笔记


第八天:抽象数据类型是指用户自定义的数据类型。虽然用户使用内部类型来定义抽象数据类型但它不是内部数据类型。

"."点操作符是访问对象变量的成员
"->"指针操作符是访问指针指向的对象变量。
包含结构类型的的结构称嵌套结构类型。嵌套结构类型可以再次被嵌套,访问被嵌套的结构成员必须用两个点操作符。
通常把类数据声明为全局性的,把类变量声明为局部的。并把类声明放在头文件中用"#include"来包含它们。
在类声明后必须有分号。可以在声明类的同时声明类变量。如下:

class empData{
char empCode[8];
float wkSalary;
}emp1,emp2;

  理论上说一切变量都是对象,但VC++的对象通常是指类变量。
对象是程序声明的某类变量,对对象的声明称做对某类实例化。
类的成员缺省是私有的。

  局部(块作用域)全局(文件作用域)

  类作用域:如果一个变量有类作用域,那么它只能在这个类中被使用。所以即使这个类变量是函数的局部变量,它的成员也未必都能被这个函数访问。
  两个关键字:public 和 private可以改变class和struct的member的缺省状态。
关键字public\private\protected叫做访问说明符。其中public和private决定了是否能在外部访问类或结构的成员。

第九天:成员函数有时被称为方法,因为它提供了一种严格的访问私有数据的方法。

class ABC{
int a;//数据成员
float b;//数据成员
char c;//数据成员
};

属性描述类的初始状态,这个类的属性包括一个整数成员、一个浮点成员、一个字符成员,所有这些成员组成了ABC类的属性。
如果类中存在函数则称为成员函数(和成员数据一样成员函数也是类的成员)。成员函数便是此对象的行为。成员函数通常被设定为公有成员。(public)。
可以用点操作符调用类中的公有数据成员和成员函数。成员函数的基本目的就是控制程序的其他部分对私有数据的访问。通常私有数据和公有函数组成了一个完整的对数据提供保护的类。
file://用以上学到的概念作一个扑克牌发牌程序,和一个彩票随机出号程序。
main()函数不仅仅是一个程序的框架,还是一个高水平的组织管理系统,管理对象并且通过发送消息控制对象的行为(通过调用成员函数)。
注意:用户只有在类变量被定义后才能赋值。只定义了类是不会有内存空间分配给它,只有定义了类变量才行。这就是说不能在类定义中初始化类的成员。
一定要在成员函数中添加参数表(可以用缺省参数表),以便在以后的程序中向成员函数传递参数。

成员函数并不是只能从对象外部到内部的单向数据通道,只要在成员函数中设置一个返回值,就很容易使对象的成员函数返回一个值到main()中。
建议为每个数据成员编写只返回一个值的只读访问成员函数,以便main()或程序其他部分访问某个数据时使用。
只把成员函数的原型放在类中,让类成为一个头文件。(包含类的简要说明,数据成员和成员函数的原型)。把成员函数体放在类说明之后,但在main()之前。在实际的编程中把所有的类定义放在一个类的头文件中,在程序中用"#include"包含类代码。最好是提供类的头文件,但事先把所有的成员函数代码编译好,在程序中使用它们时连接目标代码。
把成员函数放在类定义之外时,不要忘记在函数名前冠以作用域说明符。在每个成员函数前必须冠以它所属的类名和作用域说明符。这样才能使它和它所属的类匹配。格式如下:

类名::函数名(参数表)
例:
void ABC::getVals(void)

技巧:可以使用内联函数提高类的工作效率。
通过成员函数提供数据保护这样类不会被赋错误的值。
封装是指把几个元素包含在一个外壳中。封装就是把数据成员和成员函数联编在一个类中,这样对象可以拥有属性和行为两方面内容。

*this指针被隐式的传递给所有成员函数,它指向引起这次函数调用的对象。通过传递*this指针,VC++告诉成员函数对哪个对象进行操作。有一些情况下必须直接对*this进行操作,但大多数情况可以忽略这个指针的存在。

第十天:友元函数和友元类使得程序员在不放弃私有数据安全性的情况下,对特定的函数或类进行访问。

  要想通过一个打印函数打印类中的数据成员,要么函数是类中的一个成员,要么是友元函数。注意友元函数不是类成员,而是位于类作用域外的函数。定义友元函数时只需将它的函数原型插入类定义,象声明成员函数一样,再在函数原型前加入关键字friend即可。类本身决定友元的存在。友元函数是非成员函数,所以它无法通过this指针获得一份拷贝,因此必须给友元函数传递一个对象变量,这一点和其他非成员函数是一样的,不同的是友元函数可以访问类的私有数据。

  友元函数必须带有某类变量为参数,才能获取对象数据并对其操作。
  一个独立的友元函数可以访问多个类的数据,但必须同时为这多个类的友元。//注意:向前引用是类的原型说明。

  当一个类需要访问另一个类的某几个或全部私有数据或是私有成员函数时,将其声明为友元类。友元类是一个单独的类它可以访问另一个类中的所有成员。友元类中含有一个成员,它的类型是声明了这个友元类的类。即使一个类不是友元类,它的成员也可能是其它类的对象,但是该类将无法访问其对象成员的私有成员。

file://一个例子:
#include
#include
#include
class Boyssoftball;//类声明,因为另一个类要引用到它,如友元函数,所以必须先定义。
class Girlssoftball{
char name[25];
int age;
float batavg;
public:
void init(char N[],int A,float B);
friend void prdata(const Girlssoftball p1g,const Boyssoftball p1b);
};
void Girlssoftball::init(char N[],int A,float B){
strcpy(name,N);
age=A;
batavg=B;
}
class Boyssoftball{
char name[25];
int age;
float batavg;
public:
void init(char N[],int A,float B);
friend void prdata(const Girlssoftball p1g,const Boyssoftball p1b);
};
void Boyssoftball::init(char N[],int A,float B){
strcpy(name,N);
age=A;
batavg=B;
}
main()
{
Girlssoftball *Gplayer[3];
Boyssoftball *Bplayer[3];
for(int i=0;i<3;i++){
Gplayer[i]=new Girlssoftball;
Bplayer[i]=new Boyssoftball;
}
Gplayer[0]->init("stacy",12,1.34);
Gplayer[1]->init("suci",13,2.34);
Gplayer[2]->init("ketey",12,3.434);
Bplayer[0]->init("tom",12,4.434);
Bplayer[1]->init("jone",12,5.504);
Bplayer[2]->init("hunter",13,6.496);
for(int n=0;n<3;n++){
prdata(*Gplayer[n],*Bplayer[n]);}
for(int j=0;j<3;j++){
delete Gplayer[j];
delete Bplayer[j];
}
return 0;
}
void prdata(const Girlssoftball p1g,const Boyssoftball p1b){
cout< cout<<"player name:"< cout<<"player age:"< cout<<"player average:"< cout<<"player name:"< cout<<"player age:"< cout<<"player average:"< }

第十一天和第十二天:

  当需要对自定义数据类型进行类似于对内部数据类型进行内部操作时使用操作符重载函数。
  尽可能的编写全面的operator...()函数,以便操作符两边出现不同数据类型组合时,操作符重载依旧有效。
  再操作符重载函数中不要将多余的参数传递进去,VC++象处理其它成员函数一样负责传送接受this指针。
  不要远离操作符原来的意思。

  在重载操作符两边放置同名的类变量,可以使得一个类变量为空。
可以使用友元函数编写要把内部数据类型和自定义数据类型进行操作的,操作符重载函数。
如果将与复合操作符等价的操作符重载了,最好也重载该复合操作符。如如果重载了*最好将*=也重载。这样做的好处是有助于丰富类的功能。
在重载复合操作符时一定要返回一个this指针的间接引用。这种操作符必须返回一个左边操作符被修改的备份。
  不能精确的比较两个浮点数的值。不要轻易重载关系比较符。如与&&或||。
  如果要把内部数据作为左操作符而自定义数据类型作右操作符时,为了防止this指针的干扰,又为了能访问类中的私有成员,所以必须用友元函数。
重载递增及递减操作符也必须返回this指针。

  学习了输入<<和输出>>操作符的重载,通过编写简单的operator<<(),掌握了一种方法,将main()函数的烦琐细节除去,交给自定义的类去处理。istream和ostream的对象是和输入输出流数据相连的,由于能够存取流中数据,就还可以编写I/O操作算子函数。
下标符号也可以重载,使得余下的程序可以访问单个的成员或成员的数组元素。使用下标符号能创建安全的数组,能实现上下界自检。

第十三天:构造函数是成员函数。

  当对对象数据处理结束后可以用析构函数以自定义的方式将其清除。析构函数是用来清除数据的特殊成员函数。
  记住:构造函数和析构函数是进行对象数据的创建,初始化,清除工作的成员函数,可以重载构造函数,使一个类不止具备一个构造函数,因有时需要以这些方法中的某一种分别创建不同的对象。不能重载析构函数。

  构造函数作为成员函数和类有相同的名字。例:一个类名为:aClass,构造函数就是aClass()。构造函数没有返回值,而且不能定义其返回类型,void也不行。析构函数同样使用这一点。当编写重载函数时,只有参数表不同,通过比较其参数个数或参数类型可以区分两个重载函数。

file://包含三个构造函数的类头
class Children{
char name[25];
int age;
float Weight;
public:
void prData(void);
char * getname(void);
int getage(void);
float getWeight(void);
Children(void);//三个构造函数的声明;
Children(int,float);
Children(char *,int,float);
~Children();//析构函数
};

  析构函数作为类的成员函数也具有和类相同的名字,不同的是在函数其前多了一个~符号。名为aClass的类的析构函数~aClass()。一个类只能有一个析构函数,析构函数为成员函数没有参数,没有返回值,不能重载。
  如果构造函数为数据成员分配了内存空间,那么析构函数做的就是释放内存。只要变量在其作用域范围之内,其值都是有效的。

  VC++在定义变量时调用构造函数,在变量出了作用域时调用析构函数。时机是自动的。
  构造函数和析构函数应该是公用成员函数。
  构造函数原型可以带缺省参数。但不能和空参数同时在不带参数的情况下使用。

  当定义对象数组时,编写构造函数和析构函数。当创建数组时,VC++用构造函数构造对象数组中的每一个元素。而在出了作用域要清除数组时,由析构函数来释放所有对象。
  创建包含指针成员的对象时,应重灾赋值操作符的函数和拷贝构造函数。

 拷贝构造函数是一种特殊类型的构造函数。它的参数是一个对象变量的引用。当根据某个对象初始化新对象时,或是通过引用传递返回对象时,需要调用拷贝构造函数。

//////////////////////////////////////////////////////////////
file://字符串类string弥补了VC++没有字符串的缺憾
file://copyright rbg and 2000
file://Filename:StrClass.cpp
//////////////////////////////////////////////////////////////
#include
#include
class String{
char *st;
public:
String &operator=(const String &);
friend String operator+(const String &,const String &);
friend ostream &operator<<(ostream &,const String &);
String();
String(const char *);
String(const String &);
~String();
};
String &String::operator=(const String &s)
{
if(this==&s)
{return *this;}
delete [] st;
st=new char[strlen(s.st)+1];
strcpy(st,s.st);
return * this;
}
String::String()
{
st=''\0'';
}
String::String(const char *s)
{
st=new char[strlen(s)+1];
strcpy(st,s);
}
String::String(const String &s)
{
st=new char[strlen(s.st )+1];
strcpy(st,s.st );
}
String::~String ()
{
delete []st;
}
String operator+(const String &source,const String &tar)
{
if(!strlen(source.st))
return tar;
else if(!strlen(source.st))
return source;
String temp;
temp.st=new char[strlen(source.st)+strlen(tar.st)+1];
strcpy(temp.st,source.st );
strcat(temp.st ,tar.st );
return temp;
}
ostream &operator<<(ostream &out,const String &s)
{
out< return out;
}
////////////////////////////////////////////////////////////////////////
main(){
String myname;
String youname("zhangsan");
String hisname=youname;
myname="renbugang";
cout<<"My name is:"< cout<<"You name is:"< cout<<"His name is:"< hisname="lisi";
cout<<"His name chanage:"< String ourname;
ourname=myname+youname+hisname;
cout<<"Our name is:"< return 0;
}

第十四天:关键字static(静态),它保证了局部变量在块结束时不被破坏。

  static放在int,float等数据类型标识符前,也可以放在自定义的数据类型名前。static也称延长生存。和全局变量的静态生存期对应的是局部变量缺省的动态生存期。

  全局变量是静态的,不可能被定义为动态。全局变量自它的定义之处开始一直到源码结束都有效。若在全局变量的前面加上关键字static,则表示该全局变量拥有文件作用域。
  与全局变量相仿,在函数前冠以关键字static可以限制该函数的可见性,使得其余与这个文件相连的文件无法使用它。如果别文件使用了同名的不会发生冲突。
  如果希望另一个源文件在连接完后调用文件中的非静态函数,必须在所有调用此函数的文件中说明原型,并冠以关键字extren.

  非静态的全局变量和函数具有外部连接性,也就是说现行源文件之外的代码也可以使用这些没有用static定义的全局变量和函数,静态全局变量和函数具有内部连接性,只有现行文件可以使用。
  执行程序回到块中希望保持其变量的值,使用static定义其局部变量。
  VC++为每个类仅保留一套成员函数,每个对象都有其所属类的成员函数的函数指针。
  静态数据成员通常用来记录已创建对象的个数,例如,构造函数每次调用时将其静态成员加一,在析构函数中将相应的静态成员减一。

  使用作用域操作符::访问静态数据成员和成员函数,静态成员不于任何对象相连,所以必须通过类调用静态函数或访问静态成员。
  利用静态的成员函数访问私有的静态数据成员。
  在main()前初始化静态数据成员,在静态数据成员前加数据类型。
  使用静态数据成员记录类的使用情况,如总计或平均值。

几个概念:

  编译:将源代码(.cpp)转换为目标代码(.obj)。
  目标代码:源文件的内部二进制表示形式。是机器能理解的程序格式,源代码是程序员能理解的程序格式。
  连接:将所有的有关的目标代码连接成一个单独的可执行文件(.exe)。
  可执行文件:程序被编译连接后的状态。
  把程序分成几个文件,特别是类的头部和类的实现部分应该分离出来,这样能保证使用类的程序清晰易读。

[wangjy17908]
添加时间:2008-01-05
版权所有(C)2005-2015