C++面向对象程序编程

面向过程编程

面向过程编程POP(Procedure Oriented Programming),以功能为中心,专注于问题的解决。将整个需求分解为若干步骤,每个步骤定义为一个函数,通过逐步调用函数实现整个需求。

例如,张三丰早上开宝马去上班,面向过程编程可以梳理为如下步骤:

面向过程编程的特点,以函数为最小单位,强调的是功能行为,主要考虑怎么做(算法)。面向过程编程=数据+算法,对于给定数据经过函数处理返回结果(IPO,Input Process Output)。

面向过程的优缺点

优点

符合人类思维,各代码块分工明确,需要实现的功能拆分的清晰明了。

缺点

数据和处理该数据的函数是相互分离的。

当数据结构改变时,所有和该数据相关的函数都要修改,程序的可维护性差。

函数功能太固定,不易于复用,不易于扩展。

面向对象编程

面向对象OOP(Object Oriented Programming),面向对象编程考虑的核心不是如何将需求分解为若干步骤,而是将整个需求里面涉及的事物找出来,将事物的数据抽象为属性,事物的行为抽象为方法,再将属性和方法封装在一起形成类,由这些类相互协作完成需求。

例如,张三丰开宝马车去上班,将张三丰抽象为人类,将宝马车抽象为车类,将人和车的数据抽象为属性,动作抽象为方法。

面向对象编程的基本概念

类,描述了一组具有相同特性(数据)和相同行为(函数)的对象,例如,汽车类,书类。

对象,是现实世界实际存在的事物,是类的一个具体示例。例如,某一辆宝马,某一本书。

属性,类中的特征(数据)称为类的属性(数据成员)。例如,汽车的颜色,车牌号码,书的单价作者。

方法,类中的行为(函数)称为类的方法(成员函数)。例如,汽车有加速方法,刹车方法,转向方法等。

类与对象的关系

类与对象是抽象与具体的关系。

类是创建对象的样板,由这个样板可以创建多个具有相同属性和行为的对象。

类本质上是一种自定义数据类型,一个对象是某个类的实例。一个类的多个对象分别拥有自己的属性值,且相互独立。

成员方访问控制权限

私有访问权限 private

private 修饰的数据成员和成员函数只允许本类成员函数访问,对类的外部不可见。

保护访问权限 protected

protected 修饰的数据成员和成员函数,允许本类和本类的派生类(子类)的成员函数访问,对类外部不可见。

公有访问权限 public

public 修饰的数据成员和成员函数,允许本类和本类的派生类(子类)的成员函数访问,对类的外部可见。

/*
	class是定义类的关键字
	类名是一个标识符(类名每个单词首字母大写,其他字母小写)
	一对花括号表示类的作用域,也叫类体。分号表示类定义结束。
	关键字private、protected、public称为访问控制修饰符,描述了类成员的可见性。默认(不写)使用private。
	类中的成员函数可以在类中直接写出函数定义,也可以只写函数声明,在类的外部写出函数定义。
*/

class Rect //	定义类
{
private:

	int m_iLength;
	int m_iWidth;

public:
	
	inline int getLength();	//	方法可以是内联函数
	void setLength(int length = 1); // 方法允许有默认值
	inline int getWidth();
	//	方法允许重载
	void setWidth(int width);
	void setWidth();	
	int area();
	void show();
	
};

//	成员函数定义, 返回值 类名::方法名,函数体。
int Rect::getLength()	
{
	return m_iLength;
}

void Rect::setLength(int length)
{

	m_iLength = length;
}

int Rect::getWidth()
{
	return m_iWidth;
}

void Rect::setWidth(int width)
{
	m_iWidth = width;
}

void Rect::setWidth()
{
	m_iWidth = 1;
}

int Rect::area()
{
	return m_iLength * m_iWidth;
}

void Rect::show()
{
	cout << "m_iLength:" << m_iLength << " &m_iLength: " << &m_iLength;
	cout << " m_iWidth:" << m_iWidth << " &m_iWidth: " << &m_iWidth << endl;
}

int main()
{
	/*	
		对象是类的实例,类相当于一种自定义数据类型,对象相当于这种类型的数据。
		使用一个类一般首先是创建类的对象,然后操作对象完成计算。
	*/
	Rect r, r1; //生成Rect类的r1和r2对象。
	r.setLength(10);
	r.setWidth(2);
	cout << r.area() << endl;
	r.show();
	r1.setLength(5);
	r1.setWidth(1);
	cout << r1.area() << endl;
	r1.show();
	
	Rect r2;
	r2.setLength(); //	setLength方法的使用默认值。
	r2.setWidth(); //	setWdith()方法。
	cout << r2.area() << endl;

	/*
		对象可以通过.访问成员
		对象指针可以通过->访问成员
	*/

	Rect* p = &r2;
	p->setLength(10);
	p->setWidth(100);
	cout << p->area() << endl;

	return 0;
}

类的特殊成员

构造函数

构造函数的作用

在创建对象时,利用特定的值构造对象,将对象初始化为一个特定的状态。

构造函数的特点

构造函数的函数名与类名相同。

不能定义构造函数的函数类型(即,不能指定构造函数的返回值)。

构造函数应声明为公有函数。

构造函数不能在程序中调用,在对象创建时,构造函数被编译器自动调用。

构造函数可以重载。

如果没有显式定义构造函数,编译器会提供无参默认构造函数。例如: Rect::Rect(){ 函数体为空 }。

//构造函数

class Rect
{
private:
	int m_iLength;
	int m_iWidth;	
public:
	Rect();
	Rect(int length, int width);
	int area();
	void show();
};

Rect::Rect()
{
	m_iLength = 1;
	m_iWidth = 1;
}

Rect::Rect(int length, int width)
{
	cout << "Rect::Rect(int length, int width)" << endl;
	m_iLength = length;
	m_iWidth = width;
}

int Rect::area()
{
	return m_iLength * m_iWidth;
}

void Rect::show()
{
	cout << "m_iLength:" << m_iLength << " &m_iLength: " << &m_iLength;
	cout << " m_iWidth:" << m_iWidth << " &m_iWidth: " << &m_iWidth << endl;
}

int main()
{
	Rect r(2, 2);
	cout << r.area() << endl;
	Rect r1;
	cout << r1.area() << endl;
	return 0;
}
初始化列表

除了在构造函数中为数据初始化,还可以使用初始化列表对函数成员初始化。

如果类有常量成员数据,则只能使用初始化列表。

一般的数据成员可以使用初始化列表初始化,也可在用构造函数体中赋值。

// 构造列表

class Circle
{
private:
	const float m_PI;
	int m_radius;

public:
	Circle(int r);
	int area();
};
/*
	常量成员只能在构造列表中被初始化
	变量成员即可以在构造函数体,也可以在构造列表中初始化。

*/

Circle::Circle(int r) : m_PI(3.1415926), m_radius(r)
{		
	 //	m_radius = r; 变量初始化常用在构造函数体中初始化
}

int Circle::area()
{
	return m_PI * m_radius * m_radius;
}

int main()
{
	Circle c(2);
	cout << c.area() << endl;	
	return 0;
}

析构函数

由于类中的数据成员可以有指针,对象中可能有动态分配的内存,这就需要在对象消失前将内存释放。C++提供了析构函数来进行内存释放等清理工作。

析构函数的作用

在删除一个对象前被调用,释放该对象成员使用的动态分配内存空间,以及其他一些清理工作。

析构函数的特点

析构函数名称是: ~类名。

析构函数没有类型,也没参数,析构函数不能重载。

一个对象消失时,被编译器自动调用。

如果没有显式提供析构函数,编译器将生成一个默认的函数体为空的析构函数。

// 析构函数

class Circle
{
private:
	const float m_PI;
	int m_radius;
	char* m_name = NULL;

public:
	Circle(const char* name, int r);
	//	声明析构函数
	~Circle();
	void show();
};


Circle::Circle(const char* name, int r) : m_PI(3.1415926)
{
	cout << name << ", Circle(char* name, int r)" << endl;
	m_radius = r;
	int len = strlen(name) + 1;
	m_name = new char[len];
	strcpy_s(m_name, len, name);

}
//	实现析构函数
Circle::~Circle()
{
	cout << m_name << ", Circle::~Circle()" << endl;
	if (m_name != NULL) delete[]m_name;
}

void Circle::show()
{
	cout << m_name << ", " << m_radius << endl;
}

int main()
{
	Circle* p = new Circle("p", 1);
	char c[10] = "Circle";
	Circle circle(c, 2);
	circle.show();
	c[0] = 'X';
	circle.show();

	Circle circle1("Cricle1", 3);

	delete p;
	return 0;
}

拷贝构造函数

拷贝构造函数可以实现用一个已经存在的对象初始化新对象,拷贝构造函数的形参为该类对象的引用。

//拷贝构造

class Circle
{
private:
	const float m_PI;
	int m_radius;
	char* m_name = NULL;

public:
	Circle(const char* name, int r);
	//	拷贝构造函数的一般格式为 类名(const 类名& 形参名);
	Circle(const Circle& circle);
	~Circle();
	void show();
};

Circle::Circle(const char* name, int r) : m_PI(3.1415926)
{
	cout << name << ", Circle(char* name, int r)" << endl;
	m_radius = r;
	int len = strlen(name) + 1;
	m_name = new char[len];
	strcpy_s(m_name, len, name);

}

//	拷贝构造函数
Circle::Circle(const Circle& circle) : m_PI(3.1415926)
{
	cout << "Circle::Circle(const Circle& circle)" << endl;
	m_radius = circle.m_radius;	
	
	int len = strlen(circle.m_name) + 1;
	m_name = new char[len];
	strcpy_s(m_name, len, circle.m_name);
	
}

Circle::~Circle()
{
	cout << m_name << ", Circle::~Circle()" << endl;
	if (m_name != NULL) delete[]m_name;
}

void Circle::show()
{
	cout << m_name << ", " << m_radius << endl;
}

int main()
{
	
	Circle circle("Circle", 2);
	Circle circle1(circle); //	调用拷贝构造函数
	Circle circle2 = circle; //	调用拷贝构造函数
	
	return 0;
}

赋值函数

赋值语句把一个对象赋值给另外一个已有的同类对象时,将调用该类的赋值函数。

//赋值函数

class Circle
{
private:
	const float m_PI;
	int m_radius;
	char* m_name = NULL;

public:
	Circle(const char* name, int r);	
	Circle(const Circle& circle);
	~Circle();

	Circle& operator=(const Circle& circle);

	void show();
};

Circle::Circle(const char* name, int r) : m_PI(3.1415926)
{
	cout << name << ", Circle(char* name, int r)" << endl;
	m_radius = r;
	int len = strlen(name) + 1;
	m_name = new char[len];
	strcpy_s(m_name, len, name);

}

Circle::Circle(const Circle& circle) : m_PI(3.1415926)
{
	cout << "Circle::Circle(const Circle& circle)" << endl;
	m_radius = circle.m_radius;
	int len = strlen(circle.m_name) + 1;
	m_name = new char[len];
	strcpy_s(m_name, len, circle.m_name);

}

//	赋值函数
Circle& Circle::operator=(const Circle& circle)
{
	cout << "Circle::operator=(const Circle& circle)" << endl;
	//	this是对象的内置变量,其值是对象本身的地址。
	if (this != &circle)
	{
		delete[] m_name;
		m_radius = circle.m_radius;
		int len = strlen(circle.m_name) + 1;
		m_name = new char[len];
		strcpy_s(m_name, len, circle.m_name);		
	}
	return *this;

}

Circle::~Circle()
{
	cout << m_name << ", Circle::~Circle()" << endl;
	if (m_name != NULL) delete[]m_name;
}

void Circle::show()
{
	cout << m_name << ", " << m_radius << endl;
}

int main()
{

	Circle circle("Circle", 2);
	Circle circle1(circle); //	调用拷贝构造函数
	Circle circle2 = circle; //	调用拷贝构造函数
	Circle circle3("C3", 3); 
	circle3 = circle;		//	调用赋值函数



	return 0;
}

  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值