一 类的声明和实现
1. class tdate //声明部分
{
public:
void setdate(int y,int m,int d);
int isleapyear();
void print();
private:
int year,month,day;
}
void tdate::setdate(int y,int m,int d)//外联函数
{
year=y;
month=m;
day=d;
}
int tdate::isleapyear()
{
return(year%4==0&&y ear%100!=0)||(year%400==0);
}
void tdate::print()
{
cout< } ::为作用域运算符 标识某个成员函数是属于哪个类的 声明方式二 class tdate { public: void setdate(int y,int m,int d) //内联函数 适合函数体比较小 { year=y; month=m; day=d; } int isleapyear(){....} private: int year,month,day; }//内联函数的声明方法 将成员函数的实现 都写在类体内 ;如果函数的实现定义在类体外,则需要在函数头前面加上该函数所属的类的标识,使用作用域运算符 :: 2: 注意事项 1.类体中不允许对所定义的数据成员进行初始化 需要使用构造函数 2.类中的数据成员的类型可以是任意的,其它类的对象可以作为该类的成员,但是自身类的对象不可以,但是自身类的指针或者引用可以。 另一个类的对象作为这个类的成员时,如果另一个类的定义在后,则需要提前说明,这种说明成为引用性说明。 class N; class M { public: ... private: N n;//n是N类的对象 N类在前面说明 } class N { public: void f(M m); //m是M类的对象 M类已在前面说明 ... }; M类中使用了N类的对象n,而N类的定义又在后面,所以,对N类要提前说明 3.先声明public 公有成员,后声明私有private 私有成员 一般按照数据成员的类型大小 由小到大来说明 4.将类定义的说明部分或整个实现部分放到一个头文件中 ;也可以将声明放在一个头文件,实现放在另一个文件中 二.对象的定义 类名 对象名 tdate t1,t2,t3,* pdate,date[31],&rdate=t1; //其中多个对象用逗号隔开 pdate为指向tdate对象的指针,date为一个对象数组, rdate 为一个对象的引用。 对象成员的表示方法 对象名.成员名 对象的指针名->成员名 对象名.成员名(参数表) 对象的指针名->成员名(参数表) (* 指针).成员名 同一个类所创建的对象的数据结构是相同的,类中的成员函数是共享的。 三.对象的初始化 1.构造函数和析构函数 都是特殊的成员函数:构造函数初始化正在创建的对象;析构函数的功能是用来释放一个对象 class tdate//类声明 { public: tdate(int y,int m,int d); //构造函数 非默认 ~tdate(); //析构函数 非默认 void print(); //普通的成员函数 private: //数据成员变量 int year,month,day; } tdate::tdate(int y,int m,int d) //构造函数的实现 { year=y; month=m; day=d; cout<<"constructor called.\n"; } tdate::~tdate() //析构函数的实现 { cout<<"destructor called.\n"; } void tdate::print() //普通成员函数的实现 { cout< } 构造函数特点: a 构造函数可以写在类体内(内联),也可以写在类体外 (外联) b 构造函数为特殊的成员函数 名称同类名,不指定类型,有隐含的返回值,此值由系统内部使用。该函数可以没有参数,也可以有多个参数 c 构造函数可以重载,根据参数个数不同 d 程序不直接调用构造函数,创建对象时,系统自动调用构造函数 析构函数特点: a 同构造函数 b 类名前加~ 用来与构造函数加以区别 不指定数据类型,无参数 c 只能有一个析构函数 这一点不同于构造函数 d 通常系统自动调用 下面的两种情况 1.函数体内定义的对象 当函数结束时,系统将调用析构函数释放此对象 2.一个对象使用new运算符被动态创建时,则使用delete运算符(需要手动)释放,delete将自动调用析构函数 源代码如下: #include #include "tdate.h" void main() { tdate today(1998,4,9),tomorrow(1998,4,10); cout<<"today is"; today.print(); cout<<"tomorrow is"; tomorrow.print(); } 执行结果如下: constructor called. constructor called. today is 1998.4.9 tomorrow is 1998.4.10 destructor called. destructor called. 2.默认构造函数和默认析构函数 默认构造函数: 无参的构造函数 称为默认构造函数 a 系统自动提供的 程序员未定义 则系统自动生成 b 程序员定义的 c 系统默认构造函数 创建对象,外部类对象和静态类对象的所有数据成员默认值,自动类对象的所有数据成员为无意义值。 默认的析构函数:系统提供 的一个空函数 程序员定义的析构函数可以不是一个空函数,可以给出适当的函数体。 3.拷贝/复制构造函数 用一个已知对象来创造一个新的对象,而新创建的对象与已知对象的数据成员的值可以相同,也可以不同。 仅有一个参数,就是已知对象的引用 类名::复制构造函数名(类名 & 引用名) { 函数体 } 如果程序员未定义,则系统提供默认的复制构造函数 该类的公有成员 案例 class tpoint { public: tpoint(int x,int y){X=x;Y=y;} tpoint(tpoint & p); private: int X,Y; } tpoint::tpoint(tpoint & p) { X=p.x; Y=p.y; cout<<"adsfalsdf.\n"; } 调用: #include #include "tpoint.h" void main() { tpoint p1(5,7); tpoint p2(p1); cout<<"asdfasdf"< } 需要调用复制构造函数来由一个对象初始化另一个对象 a 明确表示一个对象初始化另一个对象 tpoint p2(p1); b 当对象作为函数实参传递给函数形参时 p=f(N); c 当一个自动存储类对象作为函数返回值时 return R; 案例代码: ... tpoint f(tpoint q); //prototype void main() { tpoint m(20,35),p(0,0); //构造函数初始化 tpoint n(m);//复制构造函数 p=f(n);//n对象作为参数传递给函数f cout<<"adsf"<<"adsfasdf"< } tpoint f(tpoint q) { ... tpoint r(x,y);//调用构造函数初始化对象 return r;//返回一个tpoint类的对象 } 代码中标红的位置是复制构造函数被调用的位置。 1.tpoint n(m) n对象被复制构造函数初始化 2.f函数 实参n传递给形参q时 会调用复制构造函数 3.f函数定义的最后 return r 函数返回的对象由于是局部变量 类型为自动存储类变量 会复制到一个无名的此类的对象,然后再返回,给原函数,所以此处会调用复制构造函数 析构函数 根据构造函数来分析 共调用6次析构函数 1.退出f函数时,调用2次析构函数,用来释放对象r和q 一个是形参对象 另一个是返回的r对象 2.主函数中,将f函数的值赋值给对象p后,无名对象(被r赋值的对象)被析构,退出主函数时,调用3此析构函数 分别释放n p和m 4.成员函数的特性 a 内联函数和外联函数 内联为定义在类体内的成员函数 执行时不转移ip执行,而是在调用内联函数处,用内联函数来替换 以节省开销,提高速度 ,类似于宏 外联为说明在类体内,但实现在类体外的成员函数 b 外联变内联 在外联函数前加上inline 案例: class A { public: A(int x,int y){X=x;Y=y;} //内联函数 int a(){return X;} //内联函数 int b(){return Y;} //内联函数 int c(); int d(); private: int X,Y; }; inline int A::c() //内联函数 { return a()+b(); } inline int A::d() //内联函数 { return c(); } #include void main() { A m(3,5); //构造函数调用 int i=m.d(); //对象的成员函数d()再调用c() 再调用a和b cout<<"d() return :"<
} 重载性 一般的成员函数,特殊的构造函数可重载,但是析构函数是不能重载的 注意重载函数中的参数个数不同 案例: class m { public: m(int x,int y){X=x;Y=y;} //构造函数 1 m(int x){X=x;Y=x*x;} //构造函数2 重载 int add(int x,int y); //成员函数1 int add(int x); //成员函数2 int add(); //成员函数3 重载 int xout(){return X;} int yout(){return Y;} private: int X,Y; }; int m::add(int x,int y) { X=x; Y=y; return X+Y; } int m::add(int x) { X=Y=x; return X+Y; } .... 4.3设置参数的默认值 成员函数和构造函数都可以设置参数的默认值 案例: class n { public: n(int a=3,int b=5,int c=7); int Aout(){return A;} int Bout(){return B;} int Cout(){return C;} private: int A,B,C; }; n::n(int a,int b,int c) //构造函数 三个参数 { A=a; B=b; C=c; } #include void main() { n x,y(9,11),z(13,15,17) cout<<"x="< cout<<"y="< cout<<"z="< } 程序执行输出如下: X=3,5,7 Y=9,11,7 z=13,15,17 未提供实参的使用原类体内的给出的默认值,给实参的使用实参值 五 静态成员 全局变量或对象和局部的静态变量或对象能解决数据共享问题 案例1: #include int g=5; //全局 void f1(),f2(); //函数原型 void main() { g=10; // 此时g是全局变量 f1(); //函数调用 f2(); //函数调用 cout< } void f1() { g=15; //修改了全局变量 } void f2() { g=20; //修改了全局变量 } 输出结果为20,函数间共享变量g, 全局变量或对象在任何位置都可以被修改。 不安全 1.静态成员包含静态数据成员和静态成员函数。它们都属于类,也属于类的所有对象。 2.静态成员可以用对象引用,也可以用类来引用。 3.静态数据成员和静态成员函数在没有对象时就已经存在,并可以用类来引用。 A 静态数据成员 实现多个对象之间的数据共享,并使用静态数据成员还不会破坏隐藏的原则,保证安全性。 静态数据成员是类的所有对象共享的成员,而不是某个对象的成员。 只存储一处,供所有对象公用。可以由共享它的任一个对象修改更新。 1.静态数据成员在定义或说明时前面加上关键字static private: int a,b,c; static int s; 其中a,b和c是非静态数据成员,而s是静态数据成员 2.静态数据成员的初始化与一般数据成员不同 在类体外进行 数据类型 类名::静态数据成员名=初值 a 初始化在类体外进行,前面不加static,以免与一般静态变量或对象相混淆 b 作用域运算符来标明它所属的类,静态数据成员属于类,不属于某个对象 3.静态数据成员被存放在静态存储区 静态数据成员是被放在静态存储区的,必须进行初始化。 案例: class nclass { ... private: static int a; //静态成员变量 声明 ... }; int nclass::a=5; //必须初始化 ... 4.引用静态数据成员的格式 类名::静态成员名 案例: class myclass { public: myclass(int a,int b,int c); //构造函数 .. private: int A,B,C; static int Sum; //静态成员变量声明 }; int myclass::sum=0; //初始化 myclass::myclass(int a,int b,int c) //构造函数的实现 { A=a; B=b; C=c; sum+=A+B+C; } void main() { myclass m(3,7,10),n(14,9,11); cout< cout< cout< cout< } 执行结果为 3,7,10 14,9,11 54 54 将m初始化时 三个数的和赋值给了sum,值为20,之后n初始化又为34 sum的总值为54;可见静态数据成员是多个对象共享的。 B 静态成员函数 同静态成员变量一样,函数也是属于类,而不是具体的对象,所以使用时可以用类名来引用静态成员函数。 静态成员函数实现的函数体中可以直接引用类中说明的静态成员,而不可以直接引用类中说明的非静态成员。 静态成员函数中要引用非静态成员时,可通过对象来引用。 #include using namespace std; class point int main() 执行结果为: (3.0,4.0) (6.0,8.0) distance is 5 案例2: #include using namespace std; //命名空间 class time //类 声明 void time12(time t) //友元实现 int main() //主函数 执行结果: 8:30 PM 20:30 10:45AM 10:45 如果形参改为引用 则函数内部的实现 修改的是实参对象的值 8:30 PM 8:30 10:45AM 10:45 友元类 一个类作为另一个类的友元,这个类的所有成员函数都是另一个类的友元函数, class x { friend class y; public:... private: int a; ... } class y { public: void display(); private: ... } y类作为x类的友元类 y中的成员函数display 是x类的友元函数 可以访问x的私有成员变量 案例: #include using namespace std; class X { int main() x=5;//b.display() y=1; x=6;//c.display() y=9; x=5;//b.display() y=9; 注意:友元的关系不可逆 y类是x类的友元类,不能说x类是y类的友元类 5.7类的作用域 类的作用域 简称类域,类的定义中由一对花括号括起来的部分。 类的成员 位于类域中。 类域中的变量不能使用auto register 和 extern等修饰符,只能使用static修饰符;函数也不能用extern修饰符 类域中的静态成员变量和静态成员函数都具有外部的连接属性 类域小于文件域 大于函数域 类A的某个成员m在下列情况下具有类A的作用域 a m出现在a的某个成员函数中,且成员函数未定义同名标识符 b a.m 表达式 c pa->m 表达式 pa为指向a对象的指针 d A::m 5.8局部类和嵌套类 函数体内定义的类称为局部类 局部类中只能使用它的外围作用域中的对象和函数进行联系, 局部类中不能说明静态成员函数,所有成员函数必须定义在类体内。 不常用 int a; void fun() //函数 { static int s; class A //类 { public: void init(int i){s=i;} }; A m; m.init(10); //A类的对象m与函数fun联系 } 嵌套类 一个类中定义的类称为嵌套类 定义嵌套类的类称为外围类。 主要目的是为了隐藏类名,减少全局的标识符。提高类的抽象能力,建立类间的主从关系 class A //外围类 { public: class B //嵌套类 { public: void bf(){...}; //成员函数 private: }; void f(); private: int a; } 说明: a B被隐藏在A中 B只能在A中使用,或者使用作用域运算符 A::B b B的访问权限与f()函数是相同的都是public c bf()函数只能在B中定义 不能在B之外定义 d B类中的成员不是A类的成员,反之一样;B的成员函数对A的成员变量没有访问权,反之一样。 综上:嵌套类可以看作普通的非嵌套类来处理。 嵌套类仅仅是语法上的嵌入 不影响功能 可以如下写法: class A { ... } class B { ... } 5.9对象的生存期 不同的存储对象生存期不同 对象从被创建开始到被释放为止的存在时间 a 局部对象:对象被构造函数初始化创建时开始 到函数或者函数体结束 调用析构函数 释放该对象 函数或者程序块内 b 静态对象:程序第一次执行所定义的静态对象时,到程序结束,对象被释放 文件中 c 全局对象:程序开始时,创建该对象 程序结束时释放对象 定义在文件中,包含在该文件的整个程序 案例 #include void fun() 练习: 一: 1.抽象类 模拟 2.class A { public: private: protected: } 3.4. 5. :: 作用域运算符 标明变量的归属 选择: 1.a 2.c 3.d 4.d 5.d 6.a 7.c 8.a 9.d 10. 二 claas 成员缺省访问权限为私有 :: 运算符用来限定成员函数所属的类 析构函数可以不为空 但是只能有一个 构造函数可以重载 析构不可重载 说明和定义对象时,前面加上类名即可,不用加上class关键字 三程序输出 1.default constructor called constructor called a=0 b=0 a=4,b=8 2. a=7,b=9 #include using namespace std; class A A::A(int i,int j):c(i,j){};//¶ÔÏóAµÄ¹¹Ô캯Êý void A::printa() B::B(int i,int j) void B::printb() int main() m.printa(); //此句输出a=7, b=9 调用B的printb来输出 三 所有对象共享此静态变量 类中的静态成员函数可以直接以类名来调用 静态成员变量直接用静态成员函数来调用 104 四 1035 789.504 五 //5.6 编程要求 using namespace std; class sum
#include
{
public:
point(double _x,double _y)
{
x=_x;y=_y;
}
void getxy();
friend double distance(point &a,point &b); //友元函数的声明
private:
double x,y;
};
void point::getxy()
{
cout<<"("<
double distance(point &a,point &b) //友元函数的实现 注意参数和声明的方式
{
double dx=a.y-b.x;
double dy=a.y-b.y;
return sqrt(dx*dx+dy*dy);
}
{
point p1(3.0,4.0),p2(6.0,8.0);
p1.getxy();
p2.getxy();
double d=distance(p1,p2);
cout<<"distance is"<
#include
{
public:
time(int _h,int _m) //内联函数
{
h=_h;m=_m;
}
friend void time12(time t); //友元
friend void time24(time t);
private:
int h,m;
};
{
if(t.h>12)
{
t.h-=12;
cout<
else
cout<
void time24(time t) //友元实现
{
cout<
{
time t1(20,30),t2(10,45); //调用构造 初始化对象
time12(t1); //友元调用
time24(t1);
time12(t2);
time24(t2);
return 0;
}
#include
{
friend class Y; //声明友元类
public:
void set(int i)
{
x=i;
}
void display()
{
cout<<"x="<
private:
int x; //成员变量
static int y; //静态成员变量
};
class Y //类声明
{
public:
Y(int i,int j); //构造函数
void display();
private:
X a; //私有成员变量为另一个类的对象
};
int X::y=1; //静态成员变量的初始化
Y::Y(int i,int j) //Y类中的Y构造函数
a.x=i; //x类对象a的x成员变量设置为i 此时x成员变量为非静态成员
X::y=j; //X类中的私有变量设置为j 因为此为构造函数,也是成员函数 即构造函数也是X类的友元函数,可以访问私有的成员变量X::y
}
void Y::display() //Y类中的display函数的实现
{
cout<<"X="<
{
X b; //b对象
b.set(5); //构造初始化
b.display();
Y c(6,9); //Y类的c对象
c.display();
b.display();
return 0;
}
#include
using namespace std;
class A //类声明 实现
{
public:
A(char * st);
~A();
private:
char string[50];
};
A::A(char * st)
{
strcpy(string,st);
cout<<"constructor called for"<
A::~A()
{
cout<<"Destructor called for"<
{
A FunObject("FunObject"); //局部对象
static A staticObject("staticobject"); //静态对象
cout<<"in fun()."<
A globalobject("globalobject"); //全局对象
int main()
{
A mainobject("mainobject"); //局部对象
cout<<"in main(),before called fun\n";
fun(); //函数调用
cout<<"in main(),after called fun\n";
return 0;
}
class B
{
public:
B();
B(int i,int j);
void printb();
private:
int a,b;
};
{
public:
A();
A(int i,int j);
void printa();
private:
B c;
};
{
c.printb();
}
{
a=i;
b=j;
}
{
cout<<"a="<}
{
A m(7,9);//设置断点 单步进入可以查看程序执行语句的顺序 此句仅调用A的构造函数 设置B对象c的a b值
return 0;
}
#include
#include
{
friend void youyuan(sum &a);
public:
sum(); //default
sum(int _x,int _y);
sum(int _x, int _y,int _z);
void print(int i=1);
static void jingtai();
private:
int x;
int y;
int z;
static int m;
};
int sum::m=1;
sum::sum()
{
x=y=0;
cout<<"default constructor!"<<"\n";
cout<<"x:"<
sum::sum(int _x,int _y)
{
x=_x;y=_y;
cout<<"constructor #1!"<<"\n";
cout<<"x:"<
sum::sum(int _x,int _y,int _z)
{
x=_x;y=_y;z=_z;
cout<<"constructor #2!"<<"\n";
cout<<"x="<
void sum::print(int i)
{
if(i==1) cout<<"默认参数:"< else cout<<"非默认参数:"<
}
void youyuan(sum &a)
{
cout<<"member is"<
void sum::jingtai()
{
cout<<"访问静态成员变量:"<
int main()
{
sum A; //构造重载
sum B(3,5);
sum C(3,5,8);
B.print(5);//成员函数非默认
A.print();//默认构造函数
C.jingtai();
youyuan(A);
youyuan(B);
return 0;
}