博文
《继承》学习笔记(2006-10-17 21:04:00)
摘要:1.向已有的类添加了新功能后的类叫做原来类的派生,原来的类叫做新类的基类。通常基类有多个派生类。
派生类的声明语法:class Dog:public Mammal
基类必须最先声明。
2.成员变量有三种限定符:private(私有型)、public(公有型)、protected(保护型)。
保护型的变量不仅可以被自己的类所访问,也可以被该类所派生出的类的成员函数所访问。而私有成员变量只可以被自己类的成员函数访问。即使是派生类也不能访问他的基类的私有成员和函数。
3.创建派生类的对象时,首先调用基类的构造函数创建对象的基类部分,然后调用派生类的构造函数,创建派生类的部分构成整个派生对象。
删除派生类的对象时,首先调用派生类的析构函数,删除对象的派生部分,然后调用基类的析构函数,删除对象的基类部分。
4.派生类的构造函数调用基类的构造函数来初始化某些成员变量,若有的成员变量希望在派生类中初始化,而基类不做初始化,则可以重载基类的构造函数,即令基类只初始化部分成员变量,然后在派生类的构造函数中显式调用该重载的构造函数。(12.3.1节)
5.派生函数可以覆盖基类函数的实现,即在派生类函数中改变基类函数的实现。
当派生类用与基类成员函数相同的返回值和签名,但却用新的实现方法创建一个函数时,就称为覆盖了该方法。签名包括:函数名、参数表以及可能用到的关键字const。
规则:一旦覆盖了任一个重载方法,那么对这个方法的所有其他原基类函数均被隐藏了,如果不想让他们被隐藏,就必须把它们全部覆盖。
若仍想调用被覆盖的函数,那可以用域限定符(::),即基类::被覆盖的方法。
6.C++扩展了其多态性,允许把派生类的对象赋给指向基类的指针。如:
Mammal *pMammal=new Dog;
Dog是Mammal派生出来的一个类。这样,就可以用该指针调用Mammal类中的任何一个方法。若想调用被Dog覆盖掉的方法,则可以用虚函数来完成。
7.虚函数。在成员函数返回类型前加关键字virtual。表明该类将做为一个基类来派生其他类。
对于虚函数,并不需要在派生类中也定义为虚函数,但继续标记为虚函数是比较好的理解手段。
正确调用函数,对于6中的pMammal指针,调用基类的虚函数,若在派生类中覆盖了该函数,那么就调用覆盖函数,若没有覆盖,就调用基类的虚函数。但......
《高级函数》学习笔记(2006-10-16 21:58:00)
摘要:1.构造函数中初始化对象的成员变量。掌握这种方法。
CAT():
ItsAge(5),
ItsWeight(8)
{}
2.复制构造函数在每次复制一个对象时调用。所有的复制构造函数均有一个参数,即对同一个类的对象的引用。使这个引用成为常量最好,这样构造函数就不必改变传递进来的对象。如:
CAT(const CAT& theCat);
3.一般的复制构造函数,执行的是成员复制,简单的将成员变量复制到新的对象中,这样容易造成内存泄漏(迷途指针)。因此,复制构造函数采取开辟新的内存区来避免这种问题的发生,这也叫深层复制。如:
CAT(const CAT& rhs)
{itsAge=new int;itsWeight=new int;
*itsAge=rhs.GetAge();*itsWeight=rhs.GetWeight();}
4.运算符重载。让对象之间(其实是对象的成员变量)可以直接进行加减乘除等运算。
重载前置运算符的格式:returnType operator op;这里op是要重载的运算符(+、—等)。如
void operator ++(){++itsVal;}
在生成的对象i进行自加执行简单的命令:++i;
如果要将自加后的对象赋给其他的对象,则只需修改函数返回值的类型为类对象。
几种不同的前置运算符的声明方法,注意返回值的类型:
classType operator ++(){++itsVal;return classType(itsVal);}
const classType& operator ++(){++itsVal;returh *this;}
在效率方面,最后一个声明语句较好。
5.后置运算符的声明。同前置运算符的区别在于加入一个整型参数。如:
void operator ++(int flag){itsVal++;}
其中参数flag并不参加任何运算,只是标明是后置运算符的声明。
6.重载加号运算符。声明如下:
classType operator+ (const classType& rhs){return classType(itsVal+rhs.GetVal());}
这样可以对实例化的两个对象进行加法运算。
7.赋值运算符。声明如下:
......
《引用》学习笔记(2006-10-13 21:01:00)
摘要:1.引用就是一个别名,当声明一个引用时,就必须把它初始化为另一个对象名,也就是目标。声明格式如下:
int &rSomRef = someInt;
对引用的操作等同于对原对象的操作。
2.对引用进行取址运算,返回的值是目标的地址,因为引用只是目标的别名。
3.引用不能够被重新赋值。若对引用重新赋值就相当于对目标重新赋值。
引用只能是对对象的引用,而不能是对类或类型的引用。
引用不能为空,即不能像空指针一样被赋为零。
4.使用引用传递参数,不是在函数的作用域中创建一个拷贝,而是直接把原对象传递给函数。因此在函数中对引用的改变也会反映到函数外。
5.指针声明的函数: void swap(int *x , int *y);
引用声明的函数: void swap(int &x , int &y);
6.若要确保被传递的引用参数不被改变,则使用const指针或引用来传递。如:
const Cat& Function(const Cat& theCat);
7.在同一个参数列表中同时使用引用、指针及采用值传递是合法的。
要避免将局部的对象以引用的方式返回,因为局部对象在函数作用域之外就会被删除。
对于引用,不能使用delete运算符。
8.如果被返回的对象是局部的,那么就必须采用按值传递,否则就加返回一个不存在的对象的引用。......
《指针》学习笔记(2006-10-12 21:39:00)
摘要:1.指针是保存内存地址的变量。
int *pAge=0;
值为零的指针被称为空指针。所有指针在定义时都应该被初始化。没有初始化的指针称为失控指针。
int age=50;
pAge=&age;
以上是为指针赋值的完整过程。
2.对于变量,类型会告诉编译器需要多少存储器去装载。但对于指针,类型并不这样做,所有指针均是4个字节。
3.使用间接引用运算符(*)来引用指针。当一个指针被间接引用时,就读取其所保存的地址处的值。
4.指针有以下三种用途:
i.处理自由存储区的数据;
ii.访问类的成员数据和函数;
iii.通过引用的方式向函数传递变量。
5.局部变量和函数形参位于栈中,寄存器则用于内存管理(如保存栈顶指针和指令指针),代码区位于代码区,全局变量区,其余的内存空间作为自由存储区,称为堆。
栈在函数返回时会自动清除。自由存储区在程序结束之前不会自动清除,所以在占用之后必须主动释放。
6.C++中使用关键字new来分配自由存储区中的内存。new的返回值是内存的地址,它必须被赋给一个指针。如:
unsigned short *pPointer=new unsigned short;
当不在使用一块内存时,使用关键字delete,它的作用是释放内存。
7.内存泄漏。
指针本身是一个局部变量,当声明指针的函数返回时,指针的作用域也就结束了,因此被丢弃了。然而由new申请的内存不会自动释放,于是这块内存就不能被其他数据使用,这种情况就称为“内存泄漏”。因此要记得使用delete来释放内存。释放后最好将指针赋值为0,变为空指针。
另一种造成内存泄漏的情况是:在没有删除一个指针之前就对其重新赋值。如:
unsigned short int *pPointer=new unsigned short int;
*pPointer=72;
pPointer=new unsigned short int;
pPonter=84;
这时保存72的内存空间变得不可用,也没办法再去释放它。应该是再次使用时,先释放。
8.也可以在自由存储区内为类的对象分配内存。如:
Cat *pCat=new Cat;
这条语句调用了默认构造函数(无参数的构造函数)。删除这类指针时,在内存释放之前会调用对象的析构函数。
也就是说,内存分配是在类对象......
《程序流程》笔记(2006-10-11 21:52:00)
摘要:1.while循环语句中的测试条件句可以是任何有效的C++语句或语句块,它也可以包括使用逻辑运算符的表达式。
2.若需要在执行while循环中的所有语句之前返回到while循环的开始处,则可以用continue语句。
若需要在满足退出循环条件之前跳出循环,则可以用break语句。
3.do...while循环在执行测试条件之前先执行循环体,保证循环体至少被执行一次。
4.for循环语句的执行过程分析
for(initilization,test,action)
statement;
initilization语句用来初始化counter的值,或是为循环做好准备。test语句可以是任何C++表达式,在每次进入循环体时都要对它进行测试。如果test测试为真,则执行循环体,然后执行action语句。
4.空for循环语句。若循环体内不放任何语句,也切记要放一条空语句(;)。
5.switch表达式可以是任何C++合法的表达式,但是该表达式的值的类型只能是int、char、enum这三种类型。......
《类的定义》相关笔记(2006-10-11 21:04:00)
摘要:1.一个类可以包含各种类型的变量,也可由其他的类组成。类中的变量称为成员变量或数据成员。类中的函数称为成员函数或类的方法。
2.声明一个类并没有为该类分配内存,只有定义类的对象时,才为对象分配内存。
3.为对象赋值,而不是为类赋值。例如:
Cat是一个类,itAge是其成员变量,则以下程序不正确
Cat.itAge=5;
4.一个类的所有成员(数据和方法)默认时均为私有的。私有成员只有在类本身的方法内访问。公有成员则可以被类的所有对象访问。
5.构造函数可以带有参数,但不能有返回值,返回空值也不行。构造函数是一个与类同名的方法。构造函数创建并初始化类的对象。析构函数在对象撤除后清除并释放分配的内存。析构函数没有参数,也没有返回值。
如果没有为类创建构造函数和析构函数,编译器会自动创建一个,即为默认构造函数。没有参数的构造函数被称为默认构造函数。编译器创建的默认构造与析构函数不带任何参数,且不执行任何操作。
只要自己创建了构造函数,系统将不再提供构造函数。因此除非自己再创建默认的构造函数,否则程序将不会有默认的构造函数。
6.如果声明类方法为const,则该方法不能更改类任何一个成员变量的值。类方法声明为常量,如下所示:
void SomeFunction() const;
良好的编程习惯是将尽可能多的方法声明为const。
7.可能通过加关键字 inline 来实现成员函数的内嵌。也可以用其他类作为自定义类的成员变量。
8.C++中结构体与类相同,只是其成员默认是公有的。但结构体没有方法。
9.类的对象在内存中的大小由类的成员变量的大小的总和来决定。类方法不占用为该对象所分配的那部分内存。
10.一个类定义了两个对象,那么两个对象可以相互访问对方的数据成员,也包括私有成员。......
《函数》笔记(2006-10-10 22:04:00)
摘要:1.函数原型(即函数声明)可以不包含参数名,而只包含函数类型。即原型中的参数名无实际意义。如:
long Area(int,int);
此外,若函数未声明返回值类型,则系统默认为返回值为整型。
2.若局部变量与全局变量同名,则在局部变量作用范围内,全局变量将被屏蔽。C++中尽量不要使用全局变量,而使用静态成员变量来替代。
3.任何一个合法的C++表达式都可以作为一个函数的变元(传递给函数以作为参数),包括常量、数学和逻辑表达式以及其他可返回值的函数,即也可以使用一个函数的返回值作为另一个函数的参数。
4.函数的值传递:即传递给函数的变元只是一个局部变量,其在函数中的变动都不影响调用函数中的值。亦即函数会为传递来的变元生成一个局部拷贝。
5.从一个函数中返回值须使用关键字 return,return后的表达式的值作为返回值传递给调用函数。return主语句执行后,其后所有的语句都不再执行。一个函数中允许有多个return语句,但只能执行一个。
6.函数默认值的声明,如:
int Function(int x=50);
因为参数名无实际意义,也可用 int Function(int =50);
对默认值的声明并不改变函数定义。但此种声明有一条限制,如果某个参数没有默认值,那该参数之前的所有参数均不可有默认值。
7.函数重载,各函数的参数要有区别,可以是参数类型、个数,或二者兼有。重载函数的返回值类型既可以相同,也可以不同。
8.内嵌函数,声明如:
inline int Area(int);
每一次调用时都会将函数代码复制到调用函数中,适用于函数体较小时。可以节省内存开销,但多次调用会增加函数体。
9.函数递归分为直接递归和间接递归。直接递归是指函数直接调用其本身。间接递归是指指函数调用了另一个函数,而被调用函数则又调用了第一个函数。......
《常量》笔记(2006-10-09 21:55:00)
摘要:1.C++有两种常用常量:字面常量和符号常量。字面常量指直接写入程序语句的数值,如:
int myAge=39;
2.符号常量是指用名字表示的常量,如同一个变量一样,不同的是在初始化之后其值不可以更改。C++有两种定义符号常量的方法:
i.用 #define 来定义。该方法定义的变量无类型,在程序中只进行简单的文本替换,即把程序中的名字用相应的数字来替代。
ii.用 const 来定义常量。该方法可以定义变量的类型,这就使得编译器可以根据类型来正确的使用常量。
3.枚举型常量。可以使用它来创建一些新的类型,再定义这些新类型的变量。如:
enum COLOR{WHITE,RED,BLUE,GREEN,BLACK};
COLOR myColor=BLUE;
每个枚举型常量都有一个整数值,若不特别指定,第一个常量值为0,其余依次增加。不过如果其中任何一个常量用一个特定的数值初始化,那么未被初始化的常量将在其前面已被初始化的常量的基础上增加。
......
sizeof()操作符说明(2006-09-28 21:11:00)
摘要:sizeof()运算符返回括号中变量或数据类型的字节数。
如果括号中是一个变量,返回的是计算机为该变量保留的存储空间的字节数。
如果括号中是一个指针,无论该指针类型是什么,其返回值总为4。
如果括号中是一个数组名,则返回值是该数组的数据类型×数组长度。
如果括号中是一个数据类型名,则返回值是该数据类型在存储空间中占用的字节数。
......
《变量与声明语句》笔记(2006-09-28 20:44:00)
摘要:1.变量名称遵循的原则
i.变量名称必须以字母或下划线开头,且只能含有字母、下划线和数字。不能含有任何其他空格、逗号或特殊符号。
ii.变量名称不能是关键字。
iii.变量名称不能由超过255个字符组成。
这些名称的选择同样适用于函数名称。
2.变量必须先声明后使用。具有相同类型的数据可以放在一条语句中声明。
3.声明语句说明:
int a;
int 告诉计算机要为一个整数保留足够的空间,a 则是告诉计算机要将保留的存储空间的第一个字节标记为名称“a”。
4.显示一个变量的地址,用地址运算符“&”。当该符号放在变量名前时,它代表的就是一个变量的地址。&price表示变量price的地址。
5.多数计算机中,short是2个字节,long是4个字节,而int可以是2个或4个字节(一般为4个字节),char是1个字节,float是4个字节,double是8个字节,bool是1个字节。
6.C++允许将定义与初始化混合使用。如:int a=5,b,c=6;
7.typedef(类型定义符)用来创建一个新名字,以取代冗长的类型定义符,如
typedef unsigned shor int USHORT;
8.当无符号整型变量的值达到其最大值时,该数值将回绕,如当一个int类型变量达到值65536时,其再加一后的值将变为0;有符号整型变量在达到最大值时也会回绕,但它是由最大的正值变为最小的负值(32767变为-32768)。
......