(自考)c++程序设计(04737)

第一章 C++语言简介

第一节 C++语言的发展简史

C++是由贝尔实验室1979年在C语言的基础上开发成功的。
C++兼容C语言,用c语言写的程序基本上可以不加修改地用于C++。
C++对C的“增强”表现在两个方面:
(1)在原来面向过程的机制基础上,增强了C语言对类型的处理。
(2)增加了面向对象的机制。
C++语言是一种编译式的、通用的、大小写敏感的编程语言,完全支持面向对象的开发模式。

第二节 C++语言的发展简史

一、基本的输入/输出

#include <iostream>
using namespace std;
int main(
{
    int a[10];
for(int i=0; i<10;i++)
cin>>a[i];
for(int i=0; i<10; i++)
cout<<a[i]<<""
cout<<endl ;

说明:
①标准输入: cin>>变量1>>变量2>>…>>变量n;
②标准输出: cout<<表达式1<<表达式2<<…<<表达式n;
③使用标准输入cin及标准输出cout前,要在程序的最前面包含:
#include //包含头文件: 输入输出流
using namespace std;//使用命名空间
④换行操作:用语句cout<<endl;或cout<<“\n”;
⑤当连续从键盘读取想要的数据时,以空格、制表符〈Tab〉键或〈Enter〉键作为分隔符。如果第一个字符是空格、〈Tab〉键或〈Enter〉键,则cin会将其忽略并清除掉,继续读取下一个字符。
⑥用户自己定义的类型的数据,不能直接用“>>”和“<<”进入输入/输出,必须对“>>”和“<<”进行运算符重载后才可以使用。

二、头文件和命名空间

头文件
前面例题中#include
每个C++程序由头文件和定义文件组成。头文件作为一种包含功能函数、数据接口声明的载体文件,主要用于保存程序的声明,而定义文件用于保存程序的实现。
头文件是用户应用程序和函数库之间的桥梁和纽带。编译时,编译器通过头文件找到对应的函数库,进而把已引用函数的实际内容导出来代替原有函数,然后再进行翻译。
常用的头文件:

  1. 标准输入输出流:
  2. 标准文件流:
  3. 标准字符串处理函数:
  4. 标准数学函数:
    除了可以使用系统提供的头文件外,程序员还可以定义自己的头文件。
    命名空间
    一个大型的程序不同模块中出现的标识符之间有可能发生重名现象,这就会引发错误。C++中为了避免名字定义冲突,特别引入了“命名空间”的定义,即namespace。命名空间的作用是为了消除同名引起的歧义。
    在程序中使用标准程序库中的标识符时,要写语句 “using namespace std;”。

三、强制类型转换运算符

当不同类型的量进行混合算术运算时,系统自动进行合理的类型转换,也可以强制转换类型。

  1. 将—种数据类型转换成另—种数据类型

stati_cast < 类型名 >(表达式)

说明: stati_cast—可以省略不写
oneint2=static_cast < int> (oneDouble);
oneint2=int(oneDouble);
oneint2= ( int) oneDouble; //圆括号
oneint2=oneDouble //自动类型转换

: int b;
float fa=30.45;
b=static_cast<int>(fa) ;
b=int(fa) ;
b=(int)fa; //旧有强制转换的形式
b=fa  //自动类型转换
  1. const_cast<类型名>(表达式)

功能:将常量指针转化成非常量的指针,并且仍然指问原来的对象;或是将常量引用转换成非常量的引用,并且仍然指向原来的对象。

:  int a=10,*q; const int ca=30;
const int *p=&a;  //不能使用常量指针p修改a的值 
q=const_cast<int *>(p)    //不能q=p
*q=20  //变量a的值变为20,不能形成*p=20 
p=&ca; //ca的值不能修改
q=const_cast<int *>(p) //不能q=p
*q=40   //*q的值为40,的值变成40
//变量ca的仍然是30

四、函数参数的默认值

C++中,可以在声明函数时为形参指定默认值。

【例1-3】定义带默认值的函数
#include<iostream>
using namespace std;
void func(int a=11,int b=22,int c=33)
{
    cout<<"a="<<a<<"b="<<b<<"c="<<c<<endl ; }
int main()
{
    func() ;
func(55);
func(77,99);
func (8,88,888);
retun 0;
}
  • C++语言规定,定义函数时,只能为函数最后面的连续若干个参数设置默认值,且在调用处也只能缺省后面的连续若干个实参。
:判断以下函数声明正确与否   //注意不是定义
void df1(int a=2, double b=3.0);//正确
void df2(int a, double b=3.0);//正确
void df3(int a=2, double b);
void f1(int a,int b=2,int c=3); //正确
void f2(int a=1,int b,int c=3) ;
void f3(int a=1,int b=2.int c):
  • C++语言规定,在函数调用处只能缺省后面的连续若干个实参,而且所有缺省的实参必须已经有默认值。
:函数调用示例
函数声明: void func(int a,int b=2,int c=3)
函数调用:func(1,22,33);
func();//错误
func(10,20);
func(5,,9);//错误

C++语言规定,指定默认值时不仅可以用常数,还可以用任何有定义的表达式作为参数的默认值。

:假设给出如下的函数及变量声明:
int Max(int m,int n)
int a, b;
void func2(int x,int y=MAX(a, b) ,int z=a-b)
{
   ……}
调用func2(4);等价于func2(4,MAX(a, b) , a-b);
func2(4,9);等价于func2(4,9,a-b);
func2(4,,10);错误
  • 注意:函数参数的默认值可以写在声明函数的地方,也可以写在定义函数的地方,但不能在两个地方都写。函数声明表示有这么个函数了,函数定义就是具体实现了。

函数声明:
int fun(int a, int b);
函数定义:
int fun(int a,int b){ int c;c=a+b;return c; }

五、引用和函数参数的传递

  1. 引用:相当于给变量起了一个别名。别名的地址与引用变量的地址是一样的。程序中使用哪个名字都是允许的。“引用”的定义格式:
    类型名 &引用名=同类型的变量名;
:int x=10;
int &a=x   //a就是x的一个引用,可以有多个引用

注意:①对象在引用前必须先初始化;=
②声明中符号“&”的位置无关紧要。
如int& a=x; int & a=x; int &a=x;等效
常引用的格式:

const类型名&引用名=同类型的变量名;

: int x=10;
int&a=x;//a就是x的一个普通引用
const int &b=x;//b就是x的一个常引用
a=20;//则x=20,b=20
x=30;//则a=30,b=30    
b=40;//错误  b是常量

注意:不能通过常引用去修改其引用的变量的值
constT&和T&是不同的类型。当声明变呈并进行初始化时,同类型之间进行初始化是允许的,不同类型之间进行初始化,有些情况下也是允许的。
2. 引用在函数中使用

  • 引用作为函数的参数数

在函数在C++中,函数调用时参数的传递有两种方式:传值和传引用。传引用是传递对象的首地址值,形参的改变就意味着实参的改变。

【例1-6】不同的参数传递方式
#include<iostream>
using namespace std;
void SVal(int a,int b)
{
   int tmp;
tmp = a; a= b; b= tmp;
cout<<"在SVal()函数中:\t\ta="<<a<<",b="<<b<<endl;
return;
}

void SRef(int& a, int& b) //a、b值互换
{
   int tmp;
tmp = a; a = b; b= tmp;
cout<<"在SRcf()函数中:\t\ta= "<<a<<", b="<<b<<endl;
return;
}
int main()
{
   int a= 10, b= 20;
cout<<"数据交换前:\t\ta="<<a<<", b="<<b<<endl<<endl;
SVal(a, b);
cout<<"调用SVal()后:\t\ta="<<a<<", b="<<b<<endl<<endl;
a= 10; b= 20; 
SRef(a, b);
cout<<"调用SpRcf()后:\t\ta="<<a<<", b="<<b<<endl;
return 0; 
}
程序的执行结果:
数据交换前:  a=10, b=20SVal()函数中:  a=20,b=10
调用SVal():   a=10,b=20SRef()函数中:  a=20,b=10
调用SRef():   a=20,b=10
  • 引用作为函数返回值

返回引用的函数原型的格式如下:

数据类型 & 函数名(参数列表);

【例1-7】引用作为函数返回值
#include <iostream>
using namespace std;
int oneX=10;
int oneY=20;
int & refValue(int & x)//函数返回值是引用{ return x;}

六、const与指针共同使用

当const与指针共同使用时,其书写的位置不同,语句含义也不同。
1)如果唯一的const位于符号*的左侧,表示指针所指数据是常量,数据不能通过本指针改变,但可以通过其他方式进行修改;指针本身是变量,可以指向其他的内存单元。

: int a1=10,a2=20.*pa1=&a1;
*pa1=30; //正确,a1变成10
const int *pa2=&a2;//pa2所指的是常量,pa2是变
*pa2=40;//错误
pa2=&a1;//正确

2)如果唯一的const位于符号*的右侧,表示指针本身是常量,不能让该指针指向其他内存地址;指针所指的数据可以通过本指针进行修改。

: int a1=10,a2=20;
int * const pa2=&a2;//指针变量pa2是常量
pa2=&a1; //错误
*pa2=40; //正确

3)在符号*的左右各有一个const时,表示指针和指针所指数据都是常量,既不能让指针指向其他地址,也不能通过指针修改所指向的内容。

: int a1=10,a2=20;
const int * const pa1=&a1;//数据和指针都是常量
pa1=&a2;//错误
*pa1=30 ;//错误
int const * const pa2=&a2;//数据和指针都是常量
pa2=&a1;//错误
*pa2=40 ;//错误

记住const的修饰规则:const修饰其左侧的内容;如果const是本行的第一个标识符,则它修饰其右侧的内容。
const int *pa2=&a2; //pa2所指的是常量
int * const pa2=&a2; //指针变量pa2是常量
const int * const pa1=&a1; //数据和指针都是常量
int const *const pa2=&a2; //数据和指针都是常量

七、内联函数

对于需要频繁调用,且代码量少的函数,可以将其定义为内联函数。编译时,编译程序将整个函数体的代码复制到调用该函数的位置。
定义内联函数的格式如下:

inline返回值类型函数名(形参表) {函数体}

如果函数体中有循环语句和switch语句则通常不定义为内联函数。

八、函数的重载

函数重载:C++允许为同一个函数定义几个版本,从而使一个函数名具有多种功能,这称为函数重载。只要分别为不同参数编制相应的函数体,就可以实现各自的功能。

:函数重载的例子1
#include <iostream>
using namespace std;
int max(int, int);//声明2个整型参数的函数原型
int max(int,int, int);//声明3个整型参数的函数原型
int main()
{
   cout<<max(36,25)<<","<<max(25,39,35)<<endl;};
int max(int m1, int m2) //定义2个整型参数的函数
{
   return (m1>m2) ? m1:m2;}
int max(int m1,int m2,int m3)  //定义3个整型参数的函数
{
   int t = max(m1,m2);return max(t,m3);}
程序运行结果36.39
:函数重载的例子2
#include <iostream>
using namespace std;
int bigger(int x, int y)
{
   if(x>y) return x; else return y;}
float bigger(float x, float y)
{
   if(x>y) return x; else return y;}
double bigger(double x, double y)
{
   if(x>y) return x; else return y;}
int main(){
   
	int x1=10,y1=20;
	float xF=30,yF=40;
	double xD=50,yD=60;
	cout<<bigger(x1,y1)<<endl;
	cout<<bigger(xF,yF)<<endl;
	cout<<bigger(xD,yD)<<endl;
}

实现函数的重载必须满足下列条件之一:

  • 参数表中对应的参数类型不同;
  • 参数表中参数个数不同;
  • 参数表中不同类型参数的次序不同。注意:
    1)两个函数的名字和参数表都是一样的,仅仅是返回值类型不同,则这两个函数不是重载的。
    例:错误的重载函数
float add(int,float);
int add(int,float);//错误

2)函数的参数采用引用的,不能区分函数,则这两个函数不是重载的。
例:错误的重载函数

void print(double);
void print(double &);//错误

3)函数调用可能会引发二义性,不能采用函数重载。例:若定义了重载函数Sum(),如下所示:

int Sum(int a, int b, int c = 0);
int Sum(int a, int b);
则函数调用语句:Sum(1,2);//调用会产生二义性

4)调用语句中的实参与函数形参的类型不完全匹配,但存在赋值兼容的情况。此时,编译器也可以确定要调用的函数。

:调用函数时进行必要的类型提升
double bigger(double x, double y){
    
if(x>y) return x;
else return y; 
}
int xl= 10,yl= 20;
float xF = 30,yF = 40;
double xD= 50, yD = 60;
cout<<bigger(xl.yF)<<endl: //int与float自动转换为double

九、指针和动态内存分配

1.指针:即指针变量,该变量储存的是一个地址,是该指针所指对象的首地址。
int a=100,*pa=&a;
int s[10],ps=s; //指针ps指向数组s的首地址
2.动态内存分配
动态分配内存一般格式为:
指针名= new 类型名;//分配
delete 指针名; //释放
当不再使用这个空间时,必须使用delete释放空间。若使用new运算符动态分配了一个数组,那么释放该数组时,语句如下: delete[]指针。

【例】演示使用new和dcletc的例子。
#includc <iostrcam>
using namespace std;
int main( ){
   
double*p;//声明double型指针
p=new double[3];
//分配3个doublc型数据的存储空间
for(int i= 0; i<3; i++) //定义对象i的初值为0
cin >> * ( p +i); //将输入数据存入指定地址
for(int j=0; j<3; j++)
cout <<*(p +j)<<" "; //将地址里的内容输出
delete []p;//释放空间}

十、用string对象处理字符串
C语言用字符数组来处理字符串,C++提供string数据类型来处理字符串。
1.声明string对象

: string strl;//声明string对象strl,值为空
string city="Beijing”;//声明string对象并初始化
string str2=city; //使用字符串变量进行初始化
char name[]=“C++程序”;
string str3= name;//使用字符数组对string变量进行初实例化
string citysf]= {
   "Beijing","Shanghai","Tianjing”};//声明string对象数组,每个数组元素都是字符串

说明:1)使用string对象,必须#include ;
2) string对象储存的是字符串的首地址,非字符串本身;sizeof(string)在32位的Dev C++中是4,在64位的Dev C++中是8。
2.string对象的操作
①、string对象可以使用cin和cout进行输入和输出

: string s1, s2;
cin>>s1>>2;
cout<<s<<","H<<s2<<endl;

②、string对象之间可以互相赋值,也可以用字符串常量和字符数组的名字对string对象进行赋值。

: string sl,s2 =”OK";
sl=”China”";
s2 = s1;   //赋值后s2的内容和si相同

③、string对象之间可以用“>”,“=”,“==”,“<=”,'<”,=”运算符进行比较。大小的判定标准是按字典序进行的,而且是大小写相关的。

: bool b;/llC++新增了bool类型,该类型只有两个取值101表示“真”,0表示“假”。
string sl=”China",s2 =”OK";b=sl>s2;l//变量b的值为0

④、使用运算符“+”对字符串进行连接

: string sl="China",s2 ="OK",s3=" ".
sl=sl+s3+s2;//连接后sl的内容“China OK”

3、string 类中的常用成员函数
在这里插入图片描述

【例1-9】字符串成员函数的使用
#include<iostream>
#include <string.h>
using namespace std;
int main()
{
    string str;//未初始化,空串
if(str.empty())
cout<<"str is NULL."<<" ,length="<<str.length()<<endl;
cout<<"str is not NULL."<<endl;
str = str.append("abcdefg");//字符串连接到当前字符串的结尾处
cout<<"str is "<<str<<", size="<<str.size()<<str.length()<<endl;
cout<<"length="<<str.length()<<endl;

const char* p = str.c_str();//p指向了字符串
strcout<<"p=<p<<endl;l/l输出p=abcdefg
cout<<"find: "<<str.find("de", 0)<<cndl; //从str的第0查找字符串"dc",成功,返回3
cout<<"find: "<<str.find( "dc",4 )<<endl;//查找失败,返回-1对应的无符号数
string strl = str.insert(4,"123");/从str的第4位置插入“123"
cout<<strl<<endl;//输出abcd123efg
return 0;
}

第三节 C++语言的程序结构

①、C++程序以.cpp作为文件扩展名,文件中包含若干个类和若干个函数。
②、程序中有且仅有一个主函数main(),程序从主函数的开始处执行,在主函数结束。
程序的结束通常是遇到了以下两种情形之一。
1)在主函数中遇到return语句。
2)执行到主函数最后面的括号}。
③、主函数中可以调用程序中定义的其他函数,但其他函数不能调用主函数,其他函数直接可以相互调用。
④、C++程序中注释有以下两种形式。
1)从/开始,到/结束,如:/………/
2)从//直到行尾,如://……
⑥、C++的格式和c一样,都很自由,一行可以写几条语句,但也要注意错落有致,增加可读性。

第二章 面向对象的基本概念

第一节 结构化程序设计

  • 结构化程序设计的基本方法:采用自顶向下、逐步求精及模块化的思想,将复杂的大问题层层分解为许多简单的小问题。

  • 结构化程序设计的三种基本结构:顺序结构、选择结构、循环结构。

  • 结构化程序设计的基本思想:数据结构+算法=程序

  • 结构化程序设计的缺点:程序在代码规模庞大时,变得难以理解、难以扩充、难以查错和难以复用。
    这种情况下,面向对象的程序设计方法就应运而生了

第二节 面向对象程序设计的概念和特点

一、面向对象思想的提出

  • 面向对象程序设计方法是20世纪90年代以来软件开发方法的主流,它继承了结构化程序设计方法的优点,同时又比较有效地改善了结构化程序设计的不足。

  • 面向对象的程序设计方法:使分析、设计和实现一个系统的方法尽可能地接近人们认识一个系统的方法。通常包括3个方面:面向对象的分析、面向对象的设计和面向对象的程序设计。

  • 面向对象技术把问题看成是对象的集合。对象具有两个特性:一是对象本身的信息,也称为属性;一是对对象的操作,也称为行为。

  • 对象=数据(属性)+函数(行为)。

  • 是对象的一个抽象。

二、面向对象程序设计的特点

面向对象程序设计的四个基本特点:抽象、封装、继承和多态。
1)抽象:将同一类事物的共同特点概括出来,这个过程就叫作“抽象”。
类是对现实世界中客观事物的抽象。对于一个具体的类,它有许多具体的个体,这些个体叫做“对象”
对象是系统中用来描述客观事物的一个实体,用对象名、属性和操作三要素来描述对象。
描述属性的数据称为成员变量数据成员,对这组属性进行操作的函数称为成员函数。对象由数据成员成员函数构成
在这里插入图片描述
例:用简单对象表示平面上的A (3.5,6.4)两个坐标点。可用如下的对象结构图表示A的对象结构:
在这里插入图片描述
例: string类的简化图—实际很复杂
①string:类名;
②str:属性;
③string:构造函数,用来初始化字符串;
④find:成员函数,用来在str字符串中检索需要的子串;
⑤size:成员函数,计算并输出str存储的单词长度;
⑥substr成员函数,用来返回str字符串中的子串。
在这里插入图片描述
2)封装:就是把对象的属性和操作结合成一个独立的单元。
封装作用:

  • 数据和操作数据的函数紧密联系起来;
  • 将对象的一部分属性和函数隐藏起来,让这部分属性和函数对外不可见,起到保护作用。
  • 另一些属性和函数对外可见,作为对对象进行操作的接口

3)继承:在编写一个“新”类的时候,以现有的类作为基础,使得新类从现有的类“派生”而来,从而达到代码扩充和代码复用的目的
4)多态:不同的对象可以调用相同名称的函数,但可导致完全不同的行为的现象称为多态性。利用多态性,程序中只需进行一般形式的函数调用,函数的实现细节留给接受函数调用的对象,这大大提高了人们解决复杂问题的能力

第三节 类的初步知识

一、类的定义

  1. 类的基本概念
    类是具有相同的属性和操作的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述,其内部包括属性(数据变量)和操作(成员函数)两个主要部分。
    类是一种用户自己构造的数据类型;
    类要先声明后使用、是具有唯一标识符的实体;
  2. 声明类
    C++中声明类的一般形式为:
    class类名{
    private:私有变量和函数
    public:公有变量和函数
    protected:保护变量和函数
    };
    说明:
    ①private是完全私有的,只有本类内可以访问,派生类和外部都不可以访问﹔
    ②protected是受保护的,只有本类内和派生类可以访问,外部不能访问;
    ③public内、外部都能访问;
    ④如无访问权限的关键字,则默认声明为private;
    ⑤不能在类的声明中对数据变量进行初始化;
    ⑥类声明中可以给出成员函数的参数的默认值;
    ⑦类中声明的任何成员不能使用extern、auto和register关键字修饰;
    存储类型
    ⑧类中可以不含有任何成员变量和成员函数,这样的类称为空类。
【例】描述点的Point类。
class Point //class是定义类的关键字,Point是类名
{
   
private :   //声明为私有访问权限
int x, y;   //私有数据成员
public:     //声明为公有访问权限
void Setxy (int a, int b);  //声明无返回值的公有成员函数
void Move ( int a, int b);//声明无返回值的公有成员函数
void Disp( );    //声明无返回值的公有成员函数
int Getx ( );   //声明返回值为int的公有成员函数
int Gety ( );   //声明返回值为int的公有成员函数 
};            //类声明以分号结束

3、定义成员函数

(::所属) 返回值类型 类名::成员函数名(形参列表){ 成员函数的函数体 }

说明:
①返回类型是指这个成员函数返回值的类型;
②类名是指成员函数所属类的名字;
③“:”是作用域运算符,用于表示其后的成员函数属于这个特定的类;

:定义属于Point类的成员函数Setxy
void Point:Setxy(int a,int b)
{
   x=a; y=b; }

④类中定义的成员函数允许重载。
⑤可以使用关键字inline将成员函数定义为内联函数(凡是出现调用该函数的地方,编译程序自动将其转换为该函数的函数体,不再在程序执行时调用该函数,大大提高了效率)。
如: inline int Point::Getx()
{return x; }
⑥如果在声明类的同时,在类体内给出成员函数的定义,就默认为内联函数,
如将声明Getx的语句"int Getx () ;”改为“int Getx (){return x; }”,则Getx为内联函数。

二、类的定义示例

【程序例2-1】定义日期类myDate
class myDate{
    
public:
myDatc();//构造函数
myDatc(int, int, int);//构造函数
void setDatc(int, int, int);//设置日期
void sctDatc(myDate);//设置日期
myDatc getDatc(); //获取日期
void setYear(int);//设置年
int getMonth();//获取月
void printDate( ) const;//打印日期
private:
int year, month, day;//成员变量,表示年、月、日
};
//在类体外定义成员函数
myDate:.myDate( )  //构造函数用来初始化
{
   ycar=1970, month=1, day=l;}
myDate:myDatc(int y, int m, int d)//构造函数
{
    year=y; month=m; day=d;}
void myDate:.setDate(int y, int m, int d)//用变量设置日期
{
    year=y; month=m; day=d;
return; }
void myDate:setDate(myDate oneD)//用对象设置日期
{
   year=oneD.year; month=oneD.month; day=oncD.day;return;};
myDate myDatc:getDate() //获取日期
{
   return *this;}
void myDate:setYear(int y)//设置年
{
    year=y;
return;}
int myDate:getMonth( )
//获取月
return month;
}
void myDate.printDate( ) const
//打印日期
{
   cout<<year <<"/"<< month <<"/"<<day;
return;
}
【程序2-2】定义学生类Student
class Student{
    public:
void setStudent(string, myDatc);//设置学生信息
void setName(string);//设置姓名
string getNamc();//获取姓名
void setBirthday(myDatc);//设置生日
myDate getBirthday();//获取生日
void printStudent( ) const;//打印信息
private:
string name;//姓名
myDate birthday;//生日
};//string 系统定义好的类,myDatc前面例题定义的类
//在类体外定义成员函数
void Student::setStudent(string s, myDate d)  //设置学生信息
{
   
name=s;
birthday.setDate(d);return;}
void Student::.setName(string n)//设置姓名
{
   name=n;
return;}
string Student::getName( )//获取姓名{return name;};
void Student:setBirthday(myDate d) //设置生日
{
   birthday.sctDatc(d);
return;
}
myDate Student::getBirthday( )//获取生日
{
   return birthday;
void Student:printStudent( ) const //打印信息
{
   cout<<"姓名: "<<namc<<"生日: ";
birthday.printDate();//调用类myDate的成员函数cout<< cndl;
};

第四节 类的示例程序剖析

一、程序结构

一个完整的C++程序包括以下几部分。
一个主函数,可以调用其他函数,但不能被调用,也称为主程序。
用户定义的任意多个的类及全局函数。
全局说明。在所有函数和类定义之外的变量说明及函数原型。
注释。
头文件。
三、创建类对象的基本形式
定义一个普通对象,即类变量的基本方法有两种。
1)类名 对象名;
类名 对象名(参数); //定义对象的同时初始化
类名 对象名=类名(参数);
2)类名 *对象指针名=new 类名;
类名 *对象指针名=new类名( )﹔
类名 *对象指针名=new类名(参数);
声明对象引用
类名 &对象引用名=对象;
声明对象指针
类名 *对象指针名=对象的地址;
声明对象数组
类名对象数组名[数组大小];

:定义了类C后,可以有如下的声明:
C al,bl;  //定义了C类的对象al和bl
C *p=&al; //定义了指向对象al的C类类型的指针p
C &R=bl;  //定义了C类类型对象bl的引用R
C A[3];   //定义了C类类型对象的数组A,含3个元素

第五节 访问对象的成员

一、使用对象访问成员变量与调用成员函数

对象访问成员变量的格式:
对象名.成员变量名
通过对象的指针访问成员变量的格式:
对象的指针->成员名
通过对象的引用访问成员变量的格式:
对象的引用.成员变量名
调用成员函数的格式:
对象名.成员函数名(参数表)
对象的指针->成员函数名(参数表)
对象的引用.成员函数名(参数表)

【程序2-3】验证类功能的驱动程序
#include <iostream>
#include <string>
using namespace std;int main()
{
   Student ss;
int y, m, d;string name_;
cout<<"请输入学生的姓名和生日,生日以‘年月日'的次序输入:";
cin >> name_ >>y >>m>>d;
ss.setStudent(name_, myDate(y, m, d));//调用成员函数
ss.printStudent(;
return 0 ; 
}

二、使用指针访问对象的成员

【程序2-4】使用指针方式的驱动程序
int main()
{
    Studcnt ss;int y, m, d;
string namc_;
Student *sp=&ss;//对象的指针
cout<<"请输入学生的姓名和生日,生日以‘年月日'的次序输cin >> name_>>y>>m>>d;
sp->sctStudent(name_, myDate(y, m, d)); //调用成员函数sp->printStudcnt();
return 0 ;
}

三、使用引用访问对象的成员

见书本【P75】程序2-5

第六节 类成员的可访问范围

一、访问范围说明符的含义

public:是公有的,使用它修饰的类的成员可以在程序的任何地方被访问。
private:是私有的,使用它修饰的类的成员仅能在本类内被访问。
protected:是保护的,它的作用介于public与private之间,使用它修饰的类的成员能在本类内及子类中被访问。一般会将成员变量声明为私有的,而将相关的成员函数声明为公有的,以便在类的外部可以调用这些成员函数来操纵成员变量。

二、成员的访问

【程序2-6】类成员的访问
#include <iostream>
using namespace std;
class Box
{
    public:
double length;
void setWidth( double wid);double gctWidth();
private:
double width;
};
//类体外定义成员函数
double Box::getWidth(){
   rcturn width;}
void Box:.setWidth(double wid) ( width=wid;
void Box:.sctWidth(double wid){
    width=wid; }
int main()
{
    Box box;
box.length=10.0;//正确,因为length是公有的
cout<< "Length of box:"<<box.length <<vendl;
//输出Length of box : 10
box.width=10.0;//错误,因为width是私有的
box.sctWidth(1 0.0);l必须使用成员函数设置宽度
cout<< "Width of box : n <<box.getWidth( ) <<cndl;
//输出Width of box : 10
return 0;
}

三、隐藏的作用

设置私有成员的机制叫作“隐藏”。
“隐藏”的优点:
1)有利于程序的修改。
2)可以避免对对象的不正确操作

第七节 标识符的作用域和可见域

C++中标识符的作用域有函数原型作用域、局部作用域(块作用域)、类作用域和命名空间作用域。
l.函数原型作用域:在声明函数原型时形参的作用范围就是函数原型作用域,这是C++程序中最小的作用域。例: double ares (double r) ;
r的作用范围就在函数area形参列表的左右括号之间。
2.局部作用域:程序中使用相匹配的一对大括号括起来的一段程序称为块。作用域局限在块内的称为局部作用域。具有局部作用域的变量也称为局部变量。

2-10 局部作用域示例
void fun(int a)
{
   	
a的作用域
int b=a;
cin>>b;
if(b>0)
{
   	b的作用域	
Int c:
....
}	c的作用域		
count<<b;		
}		

3.类作用域
设:m是类X的成员,x是类X的对象,ptr是指向类X的一个对象的指针。则对m的访问方式有如下2种:
1)类X的成员函数中可直接使用m。(除非成员函数中有同名变量)。
2)在类外,可以通过表达式x.m、X::m或者ptr->m来访问m。但注意不能违反m的访问修饰符的限定。
4.命名空间作用域
命名空间是为了消除程序各大模块之间同名引起的歧义。定义命名空间的一般形式如下:
namespace命名空间名
{命名空间内的各种声明(函数声明、类声明、…)}
在命名空间内部可以直接引用当前命名空间中声明的标识符,如果需要引用其他命名空间的标识符,需要使用下面的方式:
命名空间名::标识符名
C++提供两种形式using语句:
l) using命名空间名:.标识符名;
2) using namespace命名空间名;
使用该语句后,可以在当前作用域中直接引用该命名空间内的任何标识符。
例: using namespace std;
具有命名空间作用域的变量也称为全局变量。
标识符的可见性的一般原则:
标识符要声明在前,引用在后。
在同一个作用域中,不能声明同名的标识符。在没有互木包含关系的不同作用域中声明的同名标识符,互不影响。
如果存在两个或多个具有包含关系的作用域,外层声明一个标识符,而内层没有再次声明同名标识符,那么外层识符在内层仍然可见。如果在内层声明了同名标识符,外层标识符在内层不可见,这时称内层标识符隐藏了外层[名标识符,这种机制称为隐藏规则。

【程序2-8】作用域隐藏规则
#include <iostream>
using namespace std;int main()
{
   int a=l;
cout<<a<<"in";//输出1
for(int i=l; i<2; i++){
   
int a=2;
cout<<a<<"'n";//输出2}
cout<<a<<"n";//输出lreturn 0;}

第三章 类和对象进阶

第一节 构造函数

一、构造函数的作用

构造函数是类中的特殊成员函数。
构造函数的作用是完成对象的初始化。
给出类定义时,由程序员编写构造函数。如果程序员没有编写类的任何构造函数,则由系统自动添加一个不带参数的构造函数。

二、构造函数定义

构造函数在类体里的声明形式:
类名(形参1,形参2,…形参n) ;//也可没有形参
构造函数的定义形式:
假设数据成员为x1,x2,…x,类体外定义构造函
数时通常有3种形式:
①类名::类名(形参1,形参2,…,形参n):x1(形参1),x2(形参2), xn(形参n){ }
②类名:类名(形参1,形参2,…,形参n)
{xl =形参1;

x2=形参2;
xn=形参n;}
③类名::类名()//成员变量所赋的初值都是固定的
{x1 =初始化表达式1;
x2=初始化表达式2;

xn=初始化表达式n;}
说明:
①构造函数的名字必须和类名相同;
②在定义构造函数时不能指定返回类型,即不要返回值,即使是void类型也不可以;
③另外类可有多个构造函数,即函数重载;或重载
④构造函数的参数在排列时无顺序要求,只要保证相互对应即可;
⑤构造函数可以使用默认参数。
⑥在程序中说明一个对象时,程序自动调用构造函数来初始化该对象。

【例2-1】定义日期类myDate //第二章的例子
class myDate
{
    public:
myDate();//声明构造函数
myDatc(int);//声明构造函数
myDate(int, int);//声明构造函数
myDate(int, int, int);l/声明构造函数
……
private:
int year,month,day;l/成员变量
}
//定义构造函数
myDate::myDate( )  //固定值初始化
{
    year=1970, month=l, day=l; }
myDate:myDate( int d): year(1970), month(l)   //带1个参数
{
   day=d;}
myDate:.myDate(int m, int m) : year(1970)  //带2个参数
{
    month=m; day=d;}
myDate:.myDate(int y, int m, int d)   //带3个参数
{
    year=y; month=m; day=d;}
myDate:myDate( ) //形式3
{
   year=1970, month=1, day=l;}
可以改写为:形式1
myDate:myDate( ) : year( 1970), month(1), day(1){
   }
myDate:.myDate(int y, int m, int d) //形式2
{
    year=y; month=m; day=d;}
可以改写为:形式
myDate::myDate(int y, int m, int d) : year(y), month(m),day(d){
   }
3-3错误的构造函数定义,定义了下面两个构造函数
myDate::myDate(int d): year(1970), month(l)
{
    day = d;}
my Date::myDate(int d): year(1970), day(l)
{
   month = d;}

两个函数的函数名相同,参数相同,编译会出错。

三、构造函数的使用

当程序创建一个对象时,系统自动调用构造函数来初始化该对象。

3-6使用构造函数创建类的对象
myDate d( );   //使用无参的构造函数
myDate dl(25);  //使用1个参数的构造函数
myDate d2(10,20);
myDate d3(1971,9,18);
对象d的值:1970/1/1,对象dl的值:1970/1/25
对象d2的值:1970/10/25,对象d3的值:1971/9/18
3-7使用构造函数的默认参数创建对象
myDate::myDate(int y=1970, int m=2, int d=14)
{
    year=y; month=-m; day=d;}
myDate d( );//使用无参的构造函数
myDate dl(1980);//使用1个参数的构造函数
myDate d2(1990,3);
myDate d3(2000,4,18);
对象d的值:1970/2/14,对象dl的值:1980/2/14
对象d2的值:1990/3/14,对象d3的值:2000/4/18
3-9使用构造函数创建对象指针
myDate::myDate(int y=1970, int m=2, int d=14)//默认参数
{
    year=y; month=m; day=d;}
myDate *pd = new myDate();//p所指对象的值1970/2/14
myDate*pdl = new myDate(1955);//1955/2/14
myDate *pd2 = new myDate(1955,4);//1955/4/14
myDate *pd3 = new myDate(1955,5,13);//1955/5/13
}

注意:使用new创建对象时,下面两种都是合法的:
myDate *pd = new myDate() //带括号
myDate *pd = new myDate //不带括号
用户定义了构造函数,都会调用构造函数进行初始化;
用户未定义构造函数,对带括号的情况,系统在为成员变量分配内存的同时,将其初始化为0。不加括号时,系统只为成员变量分配内存空间,但不进行内存的初始化,成员变量的值是随机值。

:使用构造函数创建对象数组
myDate::myDate(int y=1970, int m=2, int d=14)
{
   year=y; month=m; day=d;}
myDate A[3];//对象A[0]、A[1]、A[2]的值都是1970/2/14
myDate B[3]= 
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值