C++类和对象基础

类和对象的基本概念

1.结构化程序设计
C语言使用结构化程序设计:


        程序=数据结构+算法

(1)程序由全局变量以及众多相互调用的函数组成。
(2)算法以函数的形式实现,用于对数据结构进行操作。

结构化程序设计模式:


结构化程序设

结构化程序设计的不足:


(1)结构化程序设计中,函数和其所操作的数据结构,没有直观的联系。


(2)随着程序规模的增加,程序逐渐难以理解,很难一下子看出来:


        ①某个数据结构到底有哪些函数可以对它进行操作?

        ②某个函数到底是用来操作哪些数据结构的?

        ③任何两个函数之间存在怎样的调用关系?

        ④结构化程序设计没有“封装”和“隐藏”的概念。要访问某个数据结构中的某个变量,就可以直接访问,那么当该变量的定义有改动的时候,就要把所有访问该变量的语句找出来修改,十分不利于程序的维护、扩充。

        ⑤难以查错,当某个数据结构的值不正确时,难以找出到底是那个函数导致的。

        ⑥重用:在编写某个程序时,发现其需要的某项功能,在现有的某个程序里已经有了相同或类似的实现,那么自然希望能够将那部分代码抽取出来,在新程序中使用。

         ⑦在结构化程序设计中,随着程序规模的增大,由于程序大量函数、变量之间的关系错综复杂,要抽取这部分代码,会变得十分困难。

        总之,结构化的程序,在规模庞大时,会变得难以理解,难以扩充(增加新功能),难以查错,难以重用。

面向对象的程序设计      

        软件业的目标是更快、更正确、更经济地建立软件。。如何更高效地实现函数的复用?如何更清晰的实现变量和函数的关系?使得程序更清晰更易干修改和维护。


(1)面向对象的程序设计方法,能够较好解决上述问题。

               面向对象的程序=类+类+...+类

(2)设计程序的过程,就是设计类的过程

(3)面向对象的程序设计方法:
        ①将某类客观事物共同特点(属性)归纳出来,形成一个数据结构(可以用多个变量描述事物的属性);

        ②将这类事物所能进行的行为也归纳出来,形成一个个函数,这些函数可以用来操作数据结构(这一步叫“抽象”)。

(4)然后,通过某种语法形式,将数据结构和操作该数据结构的函数“捆绑”在一起,形成一个“”,从而使得数据结构和该数据结构的算法呈现出显而易见的紧密关系,这就是“封装。”

面向对象的程序设计具有“抽象”,“封装“, ”继承”, “多态” 四个基本特点。

 二.类和对象

从客观事物抽象出类

写一个程序,输入矩形的长和宽,输出面积和周长。

比如对于“矩形”这种东西,要用一个类来表示,该如何做“抽象”呢?

矩形的属性就是长和宽。因此需要两个变量,分别代表长和宽。

一个矩形,可以有哪些行为呢(或可以对矩形进行哪些操作)?

        1.矩形可以有设置长和宽,算面积,和算周长这三种行为(当然也可以有其他行为)。

        2.这三种行为,可以各用一个函数来实现,他们都需要用到长和宽这两个变量。

        3.将长、宽变量和设置长,宽,求面积,以及求周长的三个函数“封装”在一起,就能形成一
个“矩形类”。

        4.长、宽变量成为该“矩形类”的“成员变量”,三个函数成为该类的“成员函数”。成员
变量和成员函数统称为类的成员。

实际上,“类”看上去就像“带函数的结构”。




        

//写一个程序,输入矩形的长和宽,输出面积和周长。
#include <iostream>
using namespace std;
int main()
{
	int c, k;
	int zc, mj;
	cout << "请输入长和宽:" << endl;
	cin >> c>> k;		//输入长和宽
	zc = 2*c + 2*k;
	mj = c * k;
	cout << "长为" << c << "宽为" << k << "的周长=" << zc << endl;
	cout << "长为" << c << "宽为" << k << "的面积=" << mj << endl;
	return 0;
}

使用函数:(从客观事物抽象出类)

//写一个程序,输入矩形的长和宽,输出面积和周长。
#include <iostream>
using namespace std;

class CRectangle		//创建一个CRectangle类
{
public:		//
	int w, h;		//定义宽和高
//Area(),  Perimeter(),  Init为成员函数
	int Area()		
	{
		return w * h;
	}
	int Perimeter()
	{
		return 2 * (w + h);
	}
	void Init(int w_, int h_)		//初始化
	{
		w = w_; h = h_;		//设置宽和高
	}

};		//必须要有逗号

int main()
{
	int w, h;
	CRectangle r;		//r是一个对象
	cin >> w >> h;
	r.Init(w, h);		//r.Init作用r在成员函数上面		//调用Init上CRectangle类的成员函数
	cout << r.Area() << endl << r.Perimeter() << endl;		//输出Area()和Perimeter

	return 0;
}

        (1)通过类,可以定义变量。类定义出来的变量,也称为类的实例,就是我们所说的“对象

        (2)C++中,类的名字就是用户自定义的类型的名字。可以像使用基本类型那样来使用它。CRectangle 就是一种用户自定义的类型。

对象的内存分配

(1)和结构变量一样,对象所占用的内存空间的大小,等于所有成员变量的大小之和。对于上面的CRectangle类,sizeof(CRectangle)=8

(2)每个对象各有自己的存储空间。一个对象的某个成员变量被改变了,不会影响到另一个对象。

对象间的运算
        和结构变量一样,对象之间可以用进行赋值,但是不能用==”,“!=”,“>”, “<”,“>=”,“<=”进行比较,除非这些运算符经过了“重载”。

使用类的成员变量和成员函数

        用法1:对象名.成员名

CRectangle r1,r2;
r1.w = 5;
r2.Init(5,4);

(1)lnit函数作用在 r2 上,即Init函数执行期间访问的w和h是属于r2 这个对象的,执行r2.lnit 不会影响到r1。

        用法2.指针->成员名

CRectangle r1,r2;
CRectangle * p1 = &r1;
CRectangle * p2 = &r2;
p1->w = 5;                // Init作用在p2指向的对象上
p2->Init (5,4) ;

        用法3:引用名.成员名

CRectangle r2 ;
CRectangle &rr = r2;        //引用了,rr和r2是同一个
rr.w =5;
rr.init (5,4) ;            //rr的值变了,r2的值也变
void PrintRectangle (CRectangle & r)    //CRectangle 作为参数
{
    cout <<r.Area() <<","<<r.Perimeter();    //输出Area()和Perimeter
}
CRectangle r3;    //初始化r3对象
r3.Init(5,4);
PrintRectangle (r3);

类的成员函数和类的定义分开写

class CRectangle
{
public:        //公有成员,可以在任何地方访问
    int w,h;
    int Area();    //成员函数仅在此处声明
    int Perimeter();    //成员函数仅在此处声明
    void init(int w_,int h_);
};

成员函数体在外面写:

int CRectangle::Area()    //成员函数:Area()普通名字+CRectangle类的名字。
{
    return w*h;
}

int CRectangle::Perimeter()
{
    return 2*(w+h);
}

void CRectangle::Init( int w_,int h_) 
{
    w=w_; h=h_;
}

//成员函数:Area()普通名字+CRectangle类的名字

//::(两个冒号)代表Area不是一个全局的函数,它是一个类的成员函数,属于一个CRectangle的成员函数。

        CRectangle::说明后面的函数是CRectangle类的成员函数,而非普通函数。那么,一定要通过对象或对象的指针对象的引用才能调用。

类成员的可访问范围
1.在类的定义中,用下列访问范围关键字来说明类成员可被访问的范围:
        private:  私有成员,只能在成员函数内访问

        public:  公有成员,可以在任何地方访问

        protected:  保护成员,以后再说

2.以上三种关键字出现的次数和先后次序都没有限制。

定义一个类

class className
{
private:        //说明类成员的可访问范围
私有属性和函数
public:
公有属性和函数
protected:
保护属性和函数
};

3.如过某个成员前面没有上述关键字,则缺省地被认为是私有成员

class Man 
{
    int nAge; //私有成员
    char szName[20]; //私有成员

public:
    void setName(char * szName) 
    {
        strcpy( Man :: szName,szName);
    }
};

4.在类的成员函数内部,能够访问:

        (1)当前对象的全部属性、函数;

        (2)一同类其它对象的全部属性、函数。

5.在类的成员函数以外的地方,只能够访问该类对象的公有成员

#include <iostream>
using namespace std;
class CEmployee		//创建一个员工类
{
public:			//私有成员
	char szName[30];			//名字
public :			//公有成员
	int salary;		//工资
	void setName(const char * name);		//设置姓名
	void getName(const char * name);		//获取姓名
	void averageSalary(CEmployee e1, CEmployee e2);		//平均工资
};
void CEmployee::setName(const char * name)		//设置员工的姓名
{
	strcpy(szName, name);		//可以访问类的任何成员变量和成员函数
}
void CEmployee::getName(const char * name)
{
	strcpy(szName, name);		//可以访问类的任何成员变量和成员函数
}
void CEmployee::averageSalary(CEmployee e1, CEmployee e2)		
//不是成员函数作用当前对象,它是同类的其它对象
{
	cout << e1.szName;		//ok,访问同类其他对象私有成员
	salary = (e1.salary + e2.salary) / 2;
}

int main()
{
	CEmployee e;
	strcpy(e.szName,"Tom123456789");		//编译错误,不能访问私有成员
	/*
	strcpy(e.setName, "Tom123456789");		//编译错误
	一个类的私有成员不可以在这个类的创元函数外部进行访问
	*/
	e.setName("Tom");
	e.salary=5000;
	return 0;
}

(1)设置私有成员的机制,叫“隐藏
(2)“隐藏”的目的是强制对成员变量的访问一定要通过成员函数进行,那么以后成员变量的类型等属性修改后,只需要更改成员函数即可。否则,所有直接访问成员变量的语句都需要修改。
 

“隐藏”的作用


        (1)如果将上面的程序移植到内存空间紧张的手持设备上,希望将szName改为char szName[5],若szName不是私有,那么就要找出所有类似

strcpy(e.szName, "Tom1234567889");

这样的语句进行修改,以防止数组越界。这样做很麻烦。

        (2)如果将szName变为私有,那么程序中就不可能出现(除非在类的内部)

strcpy (e.szName, "Tom1234567889");

这样的语句,所有对szName的访问都是通过成员函数来进行,比如:

e.setName("Tom12345678909887");

        (3)那么,就算szName改短了,上面的语句也不需要找出来修改.只要改setName成员函数,在里面确保不越界就可以了。

成员函数的重载及参数缺省

成员函数也可以重载
成员函数可以带缺省参数。

#include <iostream>
using namespace std;
class Location
{
private:
	int x;
	int y;
public:
	void init(int x = 0, int y = 0);
	void valuex(int val)
	{
		x = val;
	}
	int valueX()
	{
		return x;
	}
};
void Location::init(int X, int Y)
	{
		x = X;
		y = Y;
	}
int main() 
{
	Location A, B; 
	A.init(5); 
	A.valueX(5);
	cout << A.valueX();
	return 0;
}

 使用缺省参数要注意避免有函数重载时的二义

class Location 
{
private :
    int x,y;
public:
    void init( int x =0, i;
    int y= o );
    void valuex( int val = 0)
    {
         x = val; 
    }
    int valuex()
    {
         return x;
    }
};

Location A;
A.valueX()//错误,编译器无法判断调用哪个valuex
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员希西子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值