C++笔记
客观事物中任何一个事物都可以看成一个对象,对象是由一组属性和一组行为构成的。
c++中,每个对象都是由数据与函数这两部分构成,数据就是对象的属性,函数就是对象的行为。
c++中对象的类型称为类,类是一批对象的共性和特征。类是对象的抽象,对象是类的具体实例。
如何声明一个类:
class time
{
public :
//成员访问限定符
公有数据和成员函数
private :
//成员访问限定符
私有数据和成员函数
protected:
受保护数据和成员函数
};
如何定义对象:
1. 先声明类类型,然后定义对象
2. 在声明类的同时定义对象
class time
{
public :
time ();
void set_time (); //成员函数说明
void show_time ();
private :
int hour;
int minute;
int sec;
} tim1,tim2;
类的成员函数:在类体中定义的函数,同一个类的不同对象,其成员函数是共用的
,每个对象所占用的存储空间只是该对象的数据成员所占用的存储空间。
如何访问对象的中的成员:
1.对象名.对象成员
2.通过对象指针访问对象成员
time *p t1;
p=&t1;
p->hour;
3.通过对象应用访问对象成员
time t1;
time &t2=t1;
t2.hour;
怎样使用类和对象
利用构造函数对类进行初始化:
构造函数的名字必须与类名同名,它不具有任何类型,没有返回值。
在建立类对象时会自动调用构造函数。在建立对象时系统为该对象分配存储单元,此时执行构造函数,赋予初始值。
class time
{
public :
time ();
void set_time (); //成员函数说明
void show_time ();
private :
int hour;
int minute;
int sec;
};
time::time ()
//定义构造成员函数
{
//利用构造成员函数进行初始化
hour =0;
minute =0;
sec =0;
}
这种方式使该类的每一个对象的数据成员都得到同一组初值。
如何对不同对象赋予不同初值?使用带参数的构造函数。
构造函数名(类型1 形参1 )
类名 对象名(实参1 实参2 实参3...)
class box
{
public:
box(int ,int, int ); //对不同的对象赋予不同的初始值
int volume ();
private:
int height;
int width;
int length;
};
box::box(int h,int
w,int len)
{
height =h;
width =w;
length =len;
}
用参数初始化表对数据成员初始化(在函数首部初始化,而不是在函数体内对数据成员初始化)
box::box(int h,int w,int len):height(h),width(w),length(len){}
//用参数的初始化表法可以减少函数体长度
如果数据成员是数组,则应当在构造函数的函数体中用语句对其赋值,而不能在参数初始化表中对其初始化。
class student
{public:
student(int n,char s,nam[]):num(n),sex(s){strcpy(name,nam)}
private:
int num;
char sex;
char name[20];
};
构造函数的重载
在一个类中可以定义多个构造函数,以便为对象提供不同的初始化的方法,这些构造函数名字相同,二参数的个数或参数的类型不同,这称为构造函数的重载。
使用默认参数的构造函数
class box
{
public:
box(int h=10 ,int w=10, int len=10 ); //也可以写成box(int =10 ,int =10, int =10 );
int volume ();
private:
int height;
int width;
int length;
};
box::box(int h,int w,int len)
{
height =h;
width =w;
length =len;
}
注意:
1 如果构造函数的全部参数都指定了默认值,则在定义对象时可以给一个或几个实参。
2 在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。
析构函数,其作用与构造函数相反
在下列4中情况中,程序会自动执行析构函数。
1 如果在一个函数中定义了一个对象,当这个函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。
2 静态(static)局部对象在函数调用结束时对象并不释放,因此也不调用析构函数,只有在main 函数结束或者调用exit函数结束程序时,才调用static局部对象的析构函数。
3 定义了一个全局对象,
4 用new运算符动态建立了一个对象,用delete运算符释放该对象时调用析构函数。
析构函数用例:
#include<iostream>
using namespace std;
class box
{
public:
box(int ,int, int ); //对不同的对象赋予不同的初始值
int volume ();
~box()
{cout<<"construct called"<<volume()<<endl;}
private:
int height;
int width;
int length;
};
box::box(int h,int w,int len)
{
height =h;
width =w;
length =len;
}
int box::volume()
{
return (height*width*length);
}
int main()
{
box box1(12,25,30);
cout<<"the volume of box1"<<box1.volume()<<endl;
box box2(1,3,5);
cout<<"the volume of box1"<<box2.volume()<<endl;
return 0;
}
上面程序运行结果显示,先构造的后析构,后构造的先析构。相当与一个栈。
但是,并不是在任何情况都按这一原则处理的。
1 在全局范围中定义对象,它的构造函数在文本模块中所有函数执行前调用。
2 如果定义的是局部自动变量,则在建立对象时调用其构造函数,在函数调用结束时、对象释放时先调用析构函数。
3 在函数中定义静态局部对象,只在第一次调用此函数定义对象时调用构造函数一次,在main函数结束或调用exit 函数结束程序时,才调用析构函数。
对象数组(数组中每一个元素都是同类的对象)
例如:
class student
{...
};
student stud[3]={
student(12,34,45,56),
student(23,45,5,3)
student(2,4,556,3)
};
对象指针
student *st;
student stud1;
st=&stud1;
指向对象成员的指针
对象有地址,存放对象的起始地址的指针变量就是指向对象的指针变量。
对象中的成员也有地址,存放对象成员地址的指针变量就是指向对象成员的指针变量。
1.指向对象数据成员的指针
数据类型名 *指针变量名
2.指向对象成员函数的指针
数据类型名(类名::*指针变量名)(参数表名)
void(time::*p)();
指针变量名=&类名::成员函数名;
常对象成员:
1.常数据成员(其值是不能改变的,只能通过构造函数的参数初始化表对常数据成员进行初始化,任何其他函数都不能对常成员赋值)
time::time(int h)
{hour=h;} //非法,不能对其赋值
time::time(int h):hour(h){}
2.常成员函数
一般的成员函数可以引用本类中的非const数据成员,也可以修改他们。如果将数据成员函数声明为常成员函数,则只能引用本类中的数据成员,而不能修改他们。
void get_time() const;
类型名 函数名 (参数表) const;
const 是函数类型的一部分,在声明函数和定义函数的时都要有const关键字,在调用时不必加const
指向对象的常指针(指针常量)
类名*const 指针变量名; //指向对象的常指针的值不能改变,始终指向同一个对象,但可以改变其所指向的对象的值。
往往用常指针作为函数的形参,目的是不允许在函数执行过程中改变指针变量的值,使其始终指向原来的对象。
指向常对象的指针变量(常量指针)
const 类型名*指针变量
const char* ptr; //指针变量ptr指向的char 变量是常变量,不能通过ptr改变其值。
说明:
1 .如果一个变量以被声明为常变量,只能用指向常变量的指针变量指向它
2 .如果函数的形参是指向普通变量的指针变量,实参只能用指向普通变量的指针,而不能用指向const 变量的指针,这样在执行函数的过程中可以改变改变形参所指向的变量。
当希望在调用函数时对象的值不被修改,就应当把形参定义为指向常对象的指针变量,同时用对象的地址作为实参(对象可以是const或者非const型)
对象的常引用
一个变量的引用就是变量的别名。实质上,变量名和引用名都指向同一段内存地单元。
对象的动态建立和释放
有时人们希望在需要用到对象时在建立对象,在不需要用该对象时就撤销它,释放它所占用的内存空间,这样可以提高内存空间的利用率
用new运算符动态分配内存后,将返回一个指向新对象的指针,即所分配的内存空间的起始地址。
用户可以获得这个地址,并通过这个地址来访问这个对象。
box *pt;
pt=new box;
在执行new运算时,如果内存量不足,无法开辟所需的内存空间,编译系统会放回一个null。
在不需要使用由new建立的对象时,可以用delete运算符予以释放。
delete pt;
对象的赋值与复制
对象1=对象2;
对象的赋值只对其中数据成员赋值,而不对成员函数赋值。
类的数据成员中不能包括动态分配的数据,否则在赋值时可能出现严重后果。
对象的复制
类名 对象2(对象1); //用对象1复制出对象2
括号中的参数是对象,在建立对象时调用一个特殊的构造函数--复制构造函数
类名 对象2=对象1; //另一种方便用户的复制形式
对象的赋值时对一个已经存在的对象赋值,因此必须先定义被赋值的对象,才能进行赋值。
对象的赋值是从无中到有的建立一个新对象,并使它与一个已有的对象完全相同的过程。
静态成员(在同类的多个对象之间实现数据共享)
1.静态数据成员
是一种特殊的数据成员,以关键字static开头
如果希望各对象中数据成员的值是一样的,就可以把它定义为静态数据成员
1. 静态数据成员在内存中只占一份内存空间,每个对象都可以引用这个静态数据成员
2. 静态数据成员不随对象的建立而分配空间,也不随对象的撤销而释放。(静态数据成员并不是属于对象的,而是属于类的,但类的对象可以引用)
静态数据成员在程序开始运行时被分配空间,到程序结束时才释放空间。
3. 静态数据成员可以初始化,但是只能在类体外进行。不能用参数初始化列表对静态成员初始化
4. 静态数据成员尽既可以通过对象名引用,又可以通过类名来引用。
2.静态成员函数 (是类的一部分,而不是对象的一部分)
static int volume();
静态成员函数作用不是为了对象之间的沟通,而是为了能够处理静态数据成员。
静态成员函数不属于某一对象,与任何对象都无关,因此静态成员函数没有this指针,
也无法指定某个对象,也就无法访问本类中的非静态成员。
只用静态成员函数引用静态成员,而不引用非静态数据成员。
友元
1.友元函数
如果在本类以外的其他地方定义了一个函数(这个函数可以属于任何类的非成员函数,也可以是其他类的成员函数),在类体中用friend对其进行声明此函数就称为本类的友元函数。
友元函数可以访问这个类中中的私有成员。
2.友元类
将一个类声明为另一个类的朋友,
class a
{...
friend b; //在类a中声明b为其友元
...
};
关于友元类的说明:
1. 友元的关系是单向的,上面的例子中b类是a类的友元,不等于a类是b类的友元
2. 友元的关系不能传递
类模板
函数模板(对于功能相同而数据类型不同的一些函数,不必一一定义各函数,可以定义一个可对于任何类型变量进行操作的函数模板,
在调用函数时,系统会根据实参类型,取代函数模板中的类型参数,得到具体函数)
template<class 类型参数名> //声明模板类
template<class numtype>
class compare
{
public:
compare(numtype a,numtype b);
{x=a;y=b;}
numtype max()
{return (x>y)?x:y;}
numtype min()
{return (x<y)?x:y;}
private:
numtype x,y;
};
compare<int>cmp(4,6); //变成一个实际的类
template <class
numtype> //在类模板外定义方式
numtype compare<numtype>::max()
{return (x>y)?x:y;}
可以这样声明和使用类模板
1. 先写出一个实际的类
2.将此类准备改变的类型名(如int要改变成float或char)改用一个自己指定的虚拟类型名
3.在类声明前加入一行,格式为
template<class 虚拟类型参数>
4. 在类模板定义对象时用以下形式
类模板名<实际类型名>对象名;
类模板名<实际类型名>对象名(实参表);
compare<int>cmp;
compare<int>cmp(5,3);
5.如果在类模板外定义成员函数,应写出如下形式
template<class 虚拟类型参数>
函数类型 类模板名<虚拟类型参数>::成员函数名(函数参数表){...}
参考书目:《c++程序设计》谭浩强
2019-09-04 19:37:17
客观事物中任何一个事物都可以看成一个对象,对象是由一组属性和一组行为构成的。
c++中,每个对象都是由数据与函数这两部分构成,数据就是对象的属性,函数就是对象的行为。
c++中对象的类型称为类,类是一批对象的共性和特征。类是对象的抽象,对象是类的具体实例。
如何声明一个类:
class time
{
public :
//成员访问限定符
公有数据和成员函数
private :
//成员访问限定符
私有数据和成员函数
protected:
受保护数据和成员函数
};
如何定义对象:
1. 先声明类类型,然后定义对象
2. 在声明类的同时定义对象
class time
{
public :
time ();
void set_time (); //成员函数说明
void show_time ();
private :
int hour;
int minute;
int sec;
} tim1,tim2;
类的成员函数:在类体中定义的函数,同一个类的不同对象,其成员函数是共用的
,每个对象所占用的存储空间只是该对象的数据成员所占用的存储空间。
如何访问对象的中的成员:
1.对象名.对象成员
2.通过对象指针访问对象成员
time *p t1;
p=&t1;
p->hour;
3.通过对象应用访问对象成员
time t1;
time &t2=t1;
t2.hour;
怎样使用类和对象
利用构造函数对类进行初始化:
构造函数的名字必须与类名同名,它不具有任何类型,没有返回值。
在建立类对象时会自动调用构造函数。在建立对象时系统为该对象分配存储单元,此时执行构造函数,赋予初始值。
class time
{
public :
time ();
void set_time (); //成员函数说明
void show_time ();
private :
int hour;
int minute;
int sec;
};
time::time ()
//定义构造成员函数
{
//利用构造成员函数进行初始化
hour =0;
minute =0;
sec =0;
}
这种方式使该类的每一个对象的数据成员都得到同一组初值。
如何对不同对象赋予不同初值?使用带参数的构造函数。
构造函数名(类型1 形参1 )
类名 对象名(实参1 实参2 实参3...)
class box
{
public:
box(int ,int, int ); //对不同的对象赋予不同的初始值
int volume ();
private:
int height;
int width;
int length;
};
box::box(int h,int
w,int len)
{
height =h;
width =w;
length =len;
}
用参数初始化表对数据成员初始化(在函数首部初始化,而不是在函数体内对数据成员初始化)
box::box(int h,int w,int len):height(h),width(w),length(len){}
//用参数的初始化表法可以减少函数体长度
如果数据成员是数组,则应当在构造函数的函数体中用语句对其赋值,而不能在参数初始化表中对其初始化。
class student
{public:
student(int n,char s,nam[]):num(n),sex(s){strcpy(name,nam)}
private:
int num;
char sex;
char name[20];
};
构造函数的重载
在一个类中可以定义多个构造函数,以便为对象提供不同的初始化的方法,这些构造函数名字相同,二参数的个数或参数的类型不同,这称为构造函数的重载。
使用默认参数的构造函数
class box
{
public:
box(int h=10 ,int w=10, int len=10 ); //也可以写成box(int =10 ,int =10, int =10 );
int volume ();
private:
int height;
int width;
int length;
};
box::box(int h,int w,int len)
{
height =h;
width =w;
length =len;
}
注意:
1 如果构造函数的全部参数都指定了默认值,则在定义对象时可以给一个或几个实参。
2 在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。
析构函数,其作用与构造函数相反
在下列4中情况中,程序会自动执行析构函数。
1 如果在一个函数中定义了一个对象,当这个函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。
2 静态(static)局部对象在函数调用结束时对象并不释放,因此也不调用析构函数,只有在main 函数结束或者调用exit函数结束程序时,才调用static局部对象的析构函数。
3 定义了一个全局对象,
4 用new运算符动态建立了一个对象,用delete运算符释放该对象时调用析构函数。
析构函数用例:
#include<iostream>
using namespace std;
class box
{
public:
box(int ,int, int ); //对不同的对象赋予不同的初始值
int volume ();
~box()
{cout<<"construct called"<<volume()<<endl;}
private:
int height;
int width;
int length;
};
box::box(int h,int w,int len)
{
height =h;
width =w;
length =len;
}
int box::volume()
{
return (height*width*length);
}
int main()
{
box box1(12,25,30);
cout<<"the volume of box1"<<box1.volume()<<endl;
box box2(1,3,5);
cout<<"the volume of box1"<<box2.volume()<<endl;
return 0;
}
上面程序运行结果显示,先构造的后析构,后构造的先析构。相当与一个栈。
但是,并不是在任何情况都按这一原则处理的。
1 在全局范围中定义对象,它的构造函数在文本模块中所有函数执行前调用。
2 如果定义的是局部自动变量,则在建立对象时调用其构造函数,在函数调用结束时、对象释放时先调用析构函数。
3 在函数中定义静态局部对象,只在第一次调用此函数定义对象时调用构造函数一次,在main函数结束或调用exit 函数结束程序时,才调用析构函数。
对象数组(数组中每一个元素都是同类的对象)
例如:
class student
{...
};
student stud[3]={
student(12,34,45,56),
student(23,45,5,3)
student(2,4,556,3)
};
对象指针
student *st;
student stud1;
st=&stud1;
指向对象成员的指针
对象有地址,存放对象的起始地址的指针变量就是指向对象的指针变量。
对象中的成员也有地址,存放对象成员地址的指针变量就是指向对象成员的指针变量。
1.指向对象数据成员的指针
数据类型名 *指针变量名
2.指向对象成员函数的指针
数据类型名(类名::*指针变量名)(参数表名)
void(time::*p)();
指针变量名=&类名::成员函数名;
常对象成员:
1.常数据成员(其值是不能改变的,只能通过构造函数的参数初始化表对常数据成员进行初始化,任何其他函数都不能对常成员赋值)
time::time(int h)
{hour=h;} //非法,不能对其赋值
time::time(int h):hour(h){}
2.常成员函数
一般的成员函数可以引用本类中的非const数据成员,也可以修改他们。如果将数据成员函数声明为常成员函数,则只能引用本类中的数据成员,而不能修改他们。
void get_time() const;
类型名 函数名 (参数表) const;
const 是函数类型的一部分,在声明函数和定义函数的时都要有const关键字,在调用时不必加const
指向对象的常指针(指针常量)
类名*const 指针变量名; //指向对象的常指针的值不能改变,始终指向同一个对象,但可以改变其所指向的对象的值。
往往用常指针作为函数的形参,目的是不允许在函数执行过程中改变指针变量的值,使其始终指向原来的对象。
指向常对象的指针变量(常量指针)
const 类型名*指针变量
const char* ptr; //指针变量ptr指向的char 变量是常变量,不能通过ptr改变其值。
说明:
1 .如果一个变量以被声明为常变量,只能用指向常变量的指针变量指向它
2 .如果函数的形参是指向普通变量的指针变量,实参只能用指向普通变量的指针,而不能用指向const 变量的指针,这样在执行函数的过程中可以改变改变形参所指向的变量。
当希望在调用函数时对象的值不被修改,就应当把形参定义为指向常对象的指针变量,同时用对象的地址作为实参(对象可以是const或者非const型)
对象的常引用
一个变量的引用就是变量的别名。实质上,变量名和引用名都指向同一段内存地单元。
对象的动态建立和释放
有时人们希望在需要用到对象时在建立对象,在不需要用该对象时就撤销它,释放它所占用的内存空间,这样可以提高内存空间的利用率
用new运算符动态分配内存后,将返回一个指向新对象的指针,即所分配的内存空间的起始地址。
用户可以获得这个地址,并通过这个地址来访问这个对象。
box *pt;
pt=new box;
在执行new运算时,如果内存量不足,无法开辟所需的内存空间,编译系统会放回一个null。
在不需要使用由new建立的对象时,可以用delete运算符予以释放。
delete pt;
对象的赋值与复制
对象1=对象2;
对象的赋值只对其中数据成员赋值,而不对成员函数赋值。
类的数据成员中不能包括动态分配的数据,否则在赋值时可能出现严重后果。
对象的复制
类名 对象2(对象1); //用对象1复制出对象2
括号中的参数是对象,在建立对象时调用一个特殊的构造函数--复制构造函数
类名 对象2=对象1; //另一种方便用户的复制形式
对象的赋值时对一个已经存在的对象赋值,因此必须先定义被赋值的对象,才能进行赋值。
对象的赋值是从无中到有的建立一个新对象,并使它与一个已有的对象完全相同的过程。
静态成员(在同类的多个对象之间实现数据共享)
1.静态数据成员
是一种特殊的数据成员,以关键字static开头
如果希望各对象中数据成员的值是一样的,就可以把它定义为静态数据成员
1. 静态数据成员在内存中只占一份内存空间,每个对象都可以引用这个静态数据成员
2. 静态数据成员不随对象的建立而分配空间,也不随对象的撤销而释放。(静态数据成员并不是属于对象的,而是属于类的,但类的对象可以引用)
静态数据成员在程序开始运行时被分配空间,到程序结束时才释放空间。
3. 静态数据成员可以初始化,但是只能在类体外进行。不能用参数初始化列表对静态成员初始化
4. 静态数据成员尽既可以通过对象名引用,又可以通过类名来引用。
2.静态成员函数 (是类的一部分,而不是对象的一部分)
static int volume();
静态成员函数作用不是为了对象之间的沟通,而是为了能够处理静态数据成员。
静态成员函数不属于某一对象,与任何对象都无关,因此静态成员函数没有this指针,
也无法指定某个对象,也就无法访问本类中的非静态成员。
只用静态成员函数引用静态成员,而不引用非静态数据成员。
友元
1.友元函数
如果在本类以外的其他地方定义了一个函数(这个函数可以属于任何类的非成员函数,也可以是其他类的成员函数),在类体中用friend对其进行声明此函数就称为本类的友元函数。
友元函数可以访问这个类中中的私有成员。
2.友元类
将一个类声明为另一个类的朋友,
class a
{...
friend b; //在类a中声明b为其友元
...
};
关于友元类的说明:
1. 友元的关系是单向的,上面的例子中b类是a类的友元,不等于a类是b类的友元
2. 友元的关系不能传递
类模板
函数模板(对于功能相同而数据类型不同的一些函数,不必一一定义各函数,可以定义一个可对于任何类型变量进行操作的函数模板,
在调用函数时,系统会根据实参类型,取代函数模板中的类型参数,得到具体函数)
template<class 类型参数名> //声明模板类
template<class numtype>
class compare
{
public:
compare(numtype a,numtype b);
{x=a;y=b;}
numtype max()
{return (x>y)?x:y;}
numtype min()
{return (x<y)?x:y;}
private:
numtype x,y;
};
compare<int>cmp(4,6); //变成一个实际的类
template <class
numtype> //在类模板外定义方式
numtype compare<numtype>::max()
{return (x>y)?x:y;}
可以这样声明和使用类模板
1. 先写出一个实际的类
2.将此类准备改变的类型名(如int要改变成float或char)改用一个自己指定的虚拟类型名
3.在类声明前加入一行,格式为
template<class 虚拟类型参数>
4. 在类模板定义对象时用以下形式
类模板名<实际类型名>对象名;
类模板名<实际类型名>对象名(实参表);
compare<int>cmp;
compare<int>cmp(5,3);
5.如果在类模板外定义成员函数,应写出如下形式
template<class 虚拟类型参数>
函数类型 类模板名<虚拟类型参数>::成员函数名(函数参数表){...}
参考书目:《c++程序设计》谭浩强
2019-09-04 19:37:17
上一篇: 网站域名授权
下一篇: Java 创建/识别条形码、二维码