大一下第二学期期中知识复习梳理 之 c++类与对象

一、面向对象的程序设计

1、封装性(一定有)

将数据(属性)和函数(操作)封装为一个整体,称为类(非基本数据类型)
类(个人)⬅ 属性(姓名,年龄)+操作(修改姓名,读取姓名)
类实例化为对象(变量):对象(张三、李四)⬅ 类(个人)
2、继承性(派生性)(不一定有)
类(个人)⬅属性(姓名,年龄)+操作(修改姓名,读取姓名)
类(学生)⬅属性(姓名,年龄,学号)+操作(修改姓名,读取姓名,修改学号)
学生类由个人类继承(派生)而来,称为子类,继承了个人类(父类)的所有属性和操作
在继承的基础上可增加新的属性和操作
【继承性为多态性的前提】
3、多态性
个人 → 学生,操作(年度考核):根据已修学分、考试成绩
个人 → 职员,操作(年度考核):根据工作量、业绩
学生和工人是不同的人,都需要进行年度考核,但计算方法不同 → 同一接口,多种方法
多态性以继承性为前提,表现于同一父类的不同子类间
二、结构
(一)概念

相同/不同类型封装成一个整体

(二)操作

1、结构类型

struct 结构类型名

{

类型名 变量1;

类型名 变量2;
}

例子:定义复数结构类型

 2、结构变量

1)定义:关键字:struct

方式1:struct 结构类型名 结构变量名1,结构变量名2;

方式2:结构类型名 结构变量名1,结构变量名2;

方式3:定义结构类型同时定义结构变量。

2)初始化

结构类型名 结构变量名={初始化列表};

系统往往不会对局部变量整形数和浮点型数初始化为0.

若个数相同,则一一对应;若初值个数<变量个数,由前往后赋初值,无初值的后面系统自动设置。

3)操作

 3、结构指针

例子:

 

 三、类

(一)概念

 (二)成员

 (三)定义

1、类的定义

class 类名{访问限定符:成员列表}

private:写后除非通新的public,其它之后皆private,也可省略。第一个private可省。

一般数据成员定义为private类型,函数成员定义为public类型。

 2、函数成员的定义

方式一类外定义,类中声明:

返回值类型 类名:: 函数名(参数表){......};

方式二:类内定义+声明:(同一般函数定义)

返回值类型 函数名(参数表){......}

 (四)对象

 1、概念

 2、使用(同变量)

1)对象的创建

定义格式:类名 对象名

例子:complex x;

2)对象数组的创建

定义格式:类名 对象名[数组个数];

例子:complex x[10];

3)对象指针的创建

a) 定义格式:类名 *对象指针名;

例子:complex *py;

b) 初始化:指向已定义的其他同类对象(使用前须初始化!

例子:complex x,*py; py=&x;

c) 存储空间:注意创建对象指针时,并未对该指针指向的地址分配存储空间

3、对象成员的操作

 通过类对象访问,只能访问公有成员。

 只能在类内部(成员函数中) 访问私有成员,不能在类外部(通过类对象访问私有成员)。

类与对象应用实例1:

#include<iostream>
#include<iomanip>
#include<cstring>
using namespace std;
class CGoods
{
    char Name[21];
    int Amount;
    float Price;
    float Total_value;
public:
    void RegisterGoods(char [],int,float);
    void CountTotal(void) ;
    void GetName(char[]) ;
    int GetAmount(void) ;
    float GetPrice(void) ;
    float GetTotal_value(void) ;
};
void CGoods::RegisterGoods(char name[],int amount,float price)
{
    strcpy(Name,name); Amount=amount; Price=price;
}
void CGoods::CountTotal(void)
{
    Total_value=Price*Amount;
}
void CGoods::GetName(char name[])
{
    strcpy(name,Name);
}
int CGoods::GetAmount(void)
{
    return Amount;
}
float CGoods::GetPrice(void)
{
    return Price;
}
float CGoods::GetTotal_value(void)
{
    return Total_value;
}
int main()
{
    CGoods car;
    char str[21];
    int number;
    float pr;
    cout<<"请输入汽车型号:" ;
    cin.getline(str , 20) ; 
    cout<<"请依次输入汽车数量与单价:" ;
    cin>>number>>pr ;
    car.RegisterGoods(str,number,pr);
    car.CountTotal();
    str[0]='\0';
    car.GetName(str);
    cout<<setw(20)<<str<<setw(5)<<car.GetAmount() ; 
    cout<<setw(10)<<car.GetPrice()<<setw(20)<<car.GetTotal_value()<<endl ;
    return 0;
}
View Code

3、特殊的成员函数

1)初始化对象:构造函数
a)概念
 
无返回值,可多次重载。

方式一:类内定义:

类名 (参数列表) {...};

方式二:类外定义,类内声明:

类内声明:类名(参数列表);

类外定义:类名:: 类名 (参数列表){...};

特:构造函数可带默认参数,设定默认值,在声明中指定:可应对任意个数参数指定的所有情况全覆盖。

例如:类内声明时:类名(参数类型1  参数名1=默认值1,参数类型2  参数名2=默认值2,...);

c)使用

对象创建时自动调用

构造函数应用实例:

#include<iostream>
#include<iomanip>
#include<cstring>
using namespace std;
class CGoods
{
    char Name[21];
    int Amount;
    float Price;
    float Total_value;
public:
    CGoods();
    CGoods(char [],int, float);
    CGoods(char[],float);
    void GetName(char[]) ;
    int GetAmount(void) ;
    float GetPrice(void) ;
    float GetTotal_value(void) ;
};
CGoods::CGoods()
{
    Name[0]='\0'; Price=0.0; Amount=0; Total_value=0.0;
} 
CGoods::CGoods(char name[],float price)
{
    strcpy(Name,name); Price=price; Amount=0; Total_value=0.0;
}
CGoods::CGoods(char name[],int amount,float price)
{
    strcpy(Name,name); Price=price; Amount=amount; Total_value=Price*Amount;
}

void CGoods::GetName(char name[])
{
    strcpy(name,Name);
}
int CGoods::GetAmount(void)
{
    return Amount;
}
float CGoods::GetPrice(void)
{
    return Price;
}
float CGoods::GetTotal_value(void)
{
    return Total_value;
}
int main()
{
    char str[21];
    int number;
    float pr;
    cout<<"请输入汽车型号:" ;
    cin.getline(str , 20) ; 
    cout<<"请依次输入汽车数量与单价:" ;
    cin>>number>>pr ;
    CGoods car(str,number,pr);
    str[0]='\0';
    car.GetName(str);
    cout<<setw(20)<<str<<setw(5)<<car.GetAmount() ; 
    cout<<setw(10)<<car.GetPrice()<<setw(20)<<car.GetTotal_value()<<endl ;
    return 0;
}
View Code

2)通过已有的对象初始化对象:复制构造函数

a)概念

b)声明和定义

类名(类名 & 类对象){};

c)使用

复制构造函数被自动调用的情况:

途径一:一个对象通过另一个对象初始化时

complex x;
complex y(x);
complex z=x; //也是调用复制构造函数

注:complex c1,c2; c1=c2;(×)此时不为初始化,需调用运算符重载函数。

途径二:一个对象以值传递的方式传入函数时

void f1(complex c); //值传递,调用   //调用复制构造函数复制出临时新副本给形参,故开始定义时不能写此。
void f2(complex &c); //引用,不调用

 途径三:一个对象以值传递的方式从函数返回时

complex f3(); //值传递,调用
complex &f4(); //引用,不调用
总结:必须调用值传递的情况:函数参数修改而实参不改;返回某些局部变量。

注意:值传递时,复制给一个无名的临时对象。

返回局部变量时不可引用:局部变量出了函数后离开了其局部生命域;引用传递是通过获取地址访问变量,离开后局部变量被释放,原地址作废,出错。

不希望出现自动调用的复制:不必要的复制会导致额外的运行开销,性能降低。 
实例:
complex add(complex c1①,complex c2②)
{
complex c3③;
c3.real=c1.real; c3.image=c2.image;
return c3④;
}

解析:调用3次复制构造函数①②③;调用1次构造函数④;调用4次析构函数(调用多少次构造(复制构造)函数即在离开此函数结尾调用多少次析构函数)。

          此处函数若定义为complex & add():不可。c3为局部变量。同理,此函数中所有complex换为int类型定义,也不可int &add()

3)注销对象:析构函数
a)概念
唯一性。无参数无返回。 考点:可在析构函数中自主编译输出,在读程序时判断何时调用析构函数何时做相应输出。
b)定义
方式一:类内定义: 
~类名(){};
方式二:类外定义,类内声明:
类内声明:~类名();
类外定义:类名::~类名(){};

注:都是(都必须被定义为)公有函数

 4、成员对象

(1)概念

成员对象:以其他类的对象作为类成员。
类聚合:使用成员对象的技术。
例子:

(2)初始化

通过A(Person)类构造函数完成成员对象b(Birthday)的初始化
类外:(类内开头无类名及域解析标识符)
   A                 A                                       b
类名::构造函数名(参数总表):对象成员1(参数名表1),对象成员2(参数名表2),……对象成员n(参数名表n){……} 

(3)构造函数执行过程 

(4)析构函数

与不含成员对象的类一样
执行过程:相反于析构函数
对象成员应用实例:
#include<iostream>
#include<cstring>
using namespace std;
class studentID
{
    long value;
public:
    studentID(long id=0)
    {
        value=id; cout<<"赋给学生的学号:"<<value<<endl;
    }
    ~studentID(){cout<<"删除学号:"<<value<<endl;}
};
class student
{
    studentID id;
    studentID pin;
    char name[20];
public:
    student(char sname[]="no name",long sid=0):pin(222),id(sid)
    {
        cout<<"学生名:"<<sname<<endl;
        strcpy(name,sname);
    }
    ~student(){cout<<"删除学生名:"<<name<<endl;}
};
int main(){
student ss("朱明",82020132);
return 0;
}
View Code
id是成员对象,studentID的类对象是student类的成员。
sid为student类构造函数形参,又在studentID类做实参调用id构造函数。
先调用id的构造函数,再调用pin的构造函数,最后调用student的构造函数。

5、this指针

(1)概念

只读的指针变量,只有找本身不能改对象。

(2)用法

常见用法:

1、return *this;中,返回为类对象而非类对象指针。

2、类名 类对象名(*this)调用复制构造函数先存下当前的“我”

总结:可引用传递的情况:传全局变量地址;非局部变量,其他变量自定义的空间、生命域不仅限于当前函数。

四、运算符重载

(一)针对对象(适用范围)

程序员自定义类(非内置数据类型),系统未支持运算,需要程序员,通过运算符重载实现。
(二)声明与定义:关键字operator
声明:返回值类型 operator 重载的运算符(参数表);
定义:返回值类型 类名::operator 重载的运算符(参数表){};

 定义分类:

1、单目运算符:右无参数,左操作数调用。

实例:

//!a,相当于a.operator!()
complex complex::operator!();
//前置,++a,相当于a.operator++()
complex complex::operator++();
//后置,a++,相当于a.operator++(0)
complex complex::operator++(int);//恒定的int表示任何类型中的区分标识
class zoo{
int n_tiger, n_lion;
public:
zoo operator++() //前置,++a
++n_tiger;
++n_lion;
return *this;
}
zoo operator++(int) //后置,a++
zoo tmp(*this);
++n_tiger;
++n_lion;
return tmp;
}
}

2、双目运算符:1个参数。左操作数调用函数,右操作数为参数。

实例:

a+b,a调用函数,b是实参,相当于a.operator+(b),返回值不是a,而是a+b的和。
a=b,a调用函数,b是实参,相当于a.operator=(b),返回值不是a,可以是与a相等的类对象(也可以是a的引用)。
class complex{
private:
double real, image;
public:
complex(double r=0.0, double i=0.0) {real=r; image=i;};
complex(complex &c) {real=c.real; image=c.image;};
void Print(){
cout<<"Real="<<Real<<'\t'<<"Image="<<Image<<'\n';
}
complex operator+(complex); //复数相加
complex operator+(double); //复数+实数
complex operator=(complex); //复数赋值
complex operator+=(complex);
double abs(void);
complex operator*(complex); //复数相乘
complex operator/(complex); //复数相除
};

(三)应用实例:复数运算

不能改为引用原因局部参数返回值地址无用。

int main(void){
complex c1(1.0,1.0) , c2(2.0,2.0) , c3(4.0,4.0) , c;
double d=0.5 ;
c1.Print();
c=c2+c3;
//操作1:对象c2执行c2+c3的操作;操作2:对象c执行c=(操作1返回值)的操作
 c.Print();
c+=c1; c.Print();
c=c+d; c.Print(); //复数加实数
c=c3*c2; c.Print();
c=c3/c1; c.Print();
cout<<"c3的模为:"<<c3.abs()<<endl;
c=c3=c2=c1; 
//操作1:对象c2执行c2=c1的操作;操作2:对象c3执行c3=(操作1返回值)的操作;操作3:对象c执行c=(操作2返回值)的操作
c.Print(); //连续赋值
c+=c3+=c2+=c1; 
//操作1:对象c2执行c2+=c1的操作;操作2:对象c3执行c3+=(操作1返回值)的操作;操作3:对象c执行c+=(操作2返回值)的操作
c.Print(); //连续加赋值
return 0;
}

运算符重载函数实例:

 

#include<iostream>
#include<cmath>
using namespace std;
class complex
{
    double real,image;
public:
    complex(double r=0.0,double i=0.0) {real=r;image=i;}
    complex(complex &c) {real=c.real;image=c.image;}
    ~complex(){static int tot=0;cout<<++tot<<":"<<"Real="<<real<<'\t'<<"Image="<<image<<'\n';}
    void Print(){cout<<"Real="<<real<<'\t'<<"Image="<<image<<'\n';}
    complex operator +(complex);
    complex operator +(double);
    complex operator =(complex);
    complex operator +=(complex);
    double abs();
    complex operator *(complex);
    complex operator /(complex);
};
/*complex::complex(double r,double i)
{
    real=r; image=i;
}
complex::complex(complex &c)
{
    real=c.real;image=c.image;
}*/
complex complex::operator +(complex a)
{
    /*complex tmp;
    tmp.real=real+a.real;
    tmp.image=image+a.image;*/
    return complex(real+a.real,image+a.image);
}
complex complex::operator +(double d)
{
    /*complex tmp;
    tmp.real=real+a;*/
    return complex(real+d,image);
}
complex complex::operator =(complex a)
{
    real=a.real; image=a.image; 
    return *this;
}
complex complex::operator +=(complex a)
{
    real+=a.real; image+=a.image;
    return *this;
}
double complex::abs()
{
    return sqrt(real*real+image*image);
}
complex complex::operator *(complex a)
{
    double tr,ti;
    tr=real*a.real-image*a.image; ti=image*a.real+a.image*real;
    return complex(tr,ti);
}
complex complex::operator /(complex a)
{
    double tr,ti;
    tr=(real*a.real+image*a.image)/(a.real*a.real+a.image*a.image); ti=(image*a.real-a.image*real)/(a.real*a.real+a.image*a.image);
    return complex(tr,ti);
}
int main()
{
    complex c1(1.0,1.0) , c2(2.0,2.0) , c3(4.0,4.0) , c;
    double d=0.5 ;
c1.Print();
c=c2+c3; c.Print();
c+=c1; c.Print();
c=c+d; c.Print(); //复数加实数
c=c3*c2; c.Print();
c=c3/c1; c.Print();
cout<<"c3的模为:"<<c3.abs()<<endl;
c=c3=c2=c1; c.Print(); //连续赋值
c+=c3+=c2+=c1; c.Print(); //连续加赋值
    return 0;
}
View Code

 

 

 

五、友元函数

(一)声明定义

多与操作符重载函数关联使用

声明:friend 类名 operator 操作符(参数列表);

eg:(参数类型1,const 参数类型2 &) 对应(左操作数,右操作数)

定义:类名 operator 操作符(参数列表){};

定义时不要加friend,也不是成员函数。

(二)使用:同内置数据类型直接使用

例子:

class complex{
…
//声明
friend complex operator+(double, const complex&);
};
//定义时不需再加friend,也不是成员函数
complex operator+(double d, const complex& c)
{
return complex(d+c.real, c.image);
}
int main(){
…
//使用
c=d+c1; //相当于c=operator+(d, c1)
}

(三)与操作符重载函数差别

1.可用友元函数实现但无法用操作符重载函数实现的情况

双目运算符,第一个操作数为内置数据类型。eg:实数+复数

只能用友元函数实现:<< >>

2.可用操作符重载函数实现但无法用友元函数实现的情况

= [] () →

(四)使用注意

右值可为常量,左值必须为变量(可修改),但在友元函数中左右两值地位平等,故需要避免将左操作数作常量。

 (五)友元类

具有单向性:person可动用pet的所有的函数等,修改私有成员;但pet不可对person动用。

六 、静态成员

 (一)概念和内容

概念:所有同类对象共享的类成员
包括: 静态数据成员:相当于同类对象间的全局变量; 静态函数成员。
(二)定义和初始化
定义:在类定义中用关键字static修饰
初始化:在类定义外对静态数据成员做定义性说明必须做一次且只能做一次
(三)实例
#include <iostream>
using namespace std;
class Ctest{
private:
static int count;
public:
Ctest() {++count; cout<<"对象数量="<<count<<'\n'; }
~Ctest() {--count; cout<<"对象数量="<<count<<'\n'; }
};
//对静态数据定义性说明
int Ctest::count=0; 
int main(void){
Ctest a[3];
return 0;
}
编译结果:
对象数量=1 //a[0]构造函数产生
对象数量=2 //a[1]构造函数产生
对象数量=3 //a[2]构造函数产生
对象数量=2 //a[2]析构函数产生
对象数量=1 //a[1]析构函数产生
对象数量=0 //a[0]析构函数产生

 七、总结

(一)四个带系统默认的函数:

构造函数,复制构造函数,析构函数,赋值操作符重载函数(例如 complex x=y;)。

(二)封装的两种方式(非内置数据类型)

1、结构:

1)封装数据;

2)访问限定:公有。访问到结构对象即可访问其成员。

2、类与对象:

1)封装数据与函数;

2)访问到类对象不一定可以访问其成员:public型都可通过类对象访问,private只有在类内部成员函数中访问,其他参数/局部变量类对象也都可访问。

 

 
 
posted @ 2023-04-08 09:36  Au0702  阅读(104)  评论(0)    收藏  举报