面向过程与面向对象、面向对象三大特性的介绍和示例

2023-09-20 20:12:46

面向过程:将问题分解成一个个详细的步骤,然后通过函数实现每一个步骤,并依次调用
        特点:
                1、适合解决简单的问题,不需要过多的协作和抽象
                2、关注问题的解决步骤而不是问题的本质
                3、代码复用性低,扩展性差,不易维护
                4、只有封装,没有继承和多态
面向对象:通过分析问题,分解出一个个对象,然后通过不同对象之间的调用和相互协作来解决问题
        特点:
                1、适合解决复杂的问题,需要多方的协作和抽象
                2、关注问题的本质
                3、代码复用性高,扩展性好,易于维护
                4、有继承、多态、封装三大特性
        面向对象三大特性:
                提供了高度的灵活性、可维护性和扩展性,适合处理复杂的程序设计和大型项目
                1、继承:子类继承父类的属性和方法,并且子类可以在此基础上进行扩展或修改,实现了代码的复用和层次化结构
                2、封装:将一个类的某些信息隐藏在类的内部,不允许外界直接访问,而是提供某些接口实现对隐藏信息的访问和操作,这些隐藏信息提供了更好的数据安全性和代码模块化
                3、多态:一个类对象的相同方法在不同情况下有不同的表现形式,

继承:

class Person {
public:
	Person(const char* name = "name")
		: _name(name) {
		cout << "Person()" << endl;
	}

	Person(const Person& p)
		: _name(p._name) {
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p) {
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;

		return *this;
	}

	~Person() {
		cout << "~Person()" << endl;
	}
protected:
	string _name; 
};

class Student : public Person {
public:
	//子构造函数的顺序是先构造父成员,再构造子成员
	Student(const char* name, int id)
		: Person(name)	//可省略,不写就调用父类的默认构造
		, _id(id) {
		cout << "Student()" << endl;
	}

	//当手动编写子类的拷贝构造时,拷贝构造不会自动调用父类的拷贝构造,而是先切片构造父类,再手动构造子类剩余成员,
	//如果想要调用父类的拷贝构造需要在初始化列表用切片的形式手动调用
	Student(const Student& s)
		: Person(s)
		, _id(s._id) {
		cout << "Student(const Student& s)" << endl;
	}

	//Student(const Student& s)
	//	: _id(s._id) {

	//}

	Student& operator=(const Student& s) {
		if (this != &s) {
			//调用父类的赋值重载
			Person::operator=(s);
			//把自己的成员赋值
			_id = s._id;
			cout << "Student& operator=(const Student& s)" << endl;
		}

		return *this;
	}

	//析构函数会被处理成destructor
	//其他函数手动编写时需要手动调用父类的相关父函数,但是析构函数会自动调用 -- 默认且规定的析构顺序是 先子后父(只用手动析构子类比父类多的成员),与构造函数在栈帧中的顺序保持一致
	~Student() {
		cout << "~Student()" << endl;
	}
protected:
	int _id;
};

int main() {
	Student s("name",1);
	Student s1(s);
	return 0;
}

封装:

class People {
public:
	People(const string& name, const string& sex, const int& age) :_name(name), _sex(sex), _age(age) {

	}

	void introduce() {
		cout << "name:" << _name << " sex:" << _sex << " age:" << _age << endl;
	}

	void resetname(const string& name){
		_name = name;
	}
	
private:
	string _name;
	string _sex;
	int _age;
};

int main() {
	People p1("张三", "男", 18);
	p1.introduce();
	p1.resetname("李四");
	p1.introduce();
	return 0;
}

多态:

class Person {
public:
	virtual void BuyTicket() {
		cout << "全价" << endl;
	}
};

class Student : public Person {
	//对父函数进行覆盖/重写
    //override并没有实际的作用,只是标识这是一个重写
	virtual void BuyTicket() override{
		cout << "半价" << endl;
	}

	不写virtual也行,virtual属性也会自动继承,不用手动写
	//void BuyTicket() {
	//	cout << "半价" << endl;
	//}
};

//用父类指针/引用接收子类对象,实现多态
void Func(Person& p) {
	//传入的变量为	
	// 调用者的类型		指向对象的类型
	//	 ↓				  ↓
	// Person& p    =     ps 
	//		或
	// Person& p    =     st 
	//1、不满足多态时,看调用者的类型
	//2、满足多态时,看指向对象的类型
	p.BuyTicket();
}

int main() {
	Person ps;
	Student st;
	Func(ps); //全价
	Func(st); //半价

	return 0;
}

以下是一个计算图形面积的多态使用,由于每种图形的计算面积的公式都不一样,每种图形的类都继承父类的计算面积函数area(),再通过重写area()在自己的内部实现各自的面积计算 

class Shape {
public:
    //纯虚函数,由子类自己实现
    virtual double area() = 0;
};

class Circle : public Shape {
public:
    Circle(double radius) {
        _radius = radius;
    }

    double area() override {
        return 3.14 * _radius * _radius;
    }

private:
    double _radius;
};

class Rectangle : public Shape {
public:

    Rectangle(double length, double width) {
        _length = length;
        _width = width;
    }

    double area() override {
        return _length * _width;
    }
    
private:
    double _length;
    double _width;
};

int main() {
    Shape* s1 = new Circle(5);
    cout << s1->area() << endl; // 输出:78.5
    Shape* s2 = new Rectangle(10, 20);
    cout << s2->area() << endl; // 输出:200
    return 0;
}

更多推荐

@Valid注解的作用及@Valid注解与@Validated的区别

1.@Valid注解导入依赖<dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId></dependency><dependency><groupId>org.hibernate.validator</g

面试官:你是怎么理解ES6中Proxy的?使用场景?

🎬岸边的风:个人主页🔥个人专栏:《VUE》《javaScript》⛺️生活的理想,就是为了理想的生活!目录一、介绍二、用法参数handler解析Reflectget()set()deleteProperty()取消代理三、使用场景一、介绍定义:用于定义基本操作的自定义行为本质:修改的是程序默认形为,就形同于在编程语

ConfigMaps-1

文章目录主要内容一.使用YAML文件创建1.在data节点创建了一些键值:代码如下(示例):2.解释二.使用命令行创建1.创建了一个名为person的键值:代码如下(示例):2.解释3.创建了一个index.html文件,然后用--from-file来引用代码如下(示例):4.解释总结主要内容使用YAML文件创建使用命

Python 缓存库

文章目录缓存库缓存库的类型Python中有用的缓存库Python中的Redis缓存库Python中的lru_cache库Python中的其他缓存库总结缓存是一种可以存储数据以供快速访问的内存类型。它是一个小而快速的内存,用于保存经常访问的数据。缓存是至关重要的,因为它可以通过减少系统访问缓慢的主存储器的次数来提高系统性

【从入门到起飞】JavaAPI—System,Runtime,Object,Objects类

🎊专栏【JavaSE】🍔喜欢的诗句:更喜岷山千里雪三军过后尽开颜。🎆音乐分享【如愿】🎄欢迎并且感谢大家指出小吉的问题🥰文章目录🍔System类⭐exit()⭐currentTimeMillis()🎄用处⭐arraycopy()🍔Runtime类⭐创建对象⭐exit()⭐availableProcesso

写一篇nginx配置指南

nginx.conf配置找到Nginx的安装目录下的nginx.conf文件,该文件负责Nginx的基础功能配置。配置文件概述Nginx的主配置文件(conf/nginx.conf)按以下结构组织:配置块功能描述全局块与Nginx运行相关的全局设置events块与网络连接有关的设置http块代理、缓存、日志、虚拟主机等

【计算机网络】网络编程接口 Socket API 解读(6)

Socket是网络协议栈暴露给编程人员的API,相比复杂的计算机网络协议,API对关键操作和配置数据进行了抽象,简化了程序编程。本文讲述的socket内容源自Linuxman。本文主要对各API进行详细介绍,从而更好的理解socket编程。recvrecv()遵循POSIX.1-20081.库标准c库,libc,-lc

Ubuntu 安装 CUDA 与 CUDNN GPU加速引擎

一、NVIDIA(英伟达)显卡驱动安装NVIDIA显卡驱动可以通过指令sudoaptpurgenvidia*删除以前安装的NVIDIA驱动版本,重新安装。1.1.关闭系统自带驱动nouveau注意!在安装NVIDIA驱动以前需要禁止系统自带显卡驱动nouveau:可以先通过指令lsmod|grepnouveau查看no

嵌入式笔试面试刷题(day11)

文章目录前言一、字节流,数据报,报文二、makefile怎么引入库和模块三、多次free一块内存空间会怎么样四、字符操作函数越界会发生什么五、QT中一个信号可以连接多个槽函数吗六、QT中一个槽函数可以对应多个信号吗总结前言本篇文章继续刷题。一、字节流,数据报,报文1.数据报(Datagram):数据报是一种独立的、特定

Linux:基础开发工具之Makefile和缓冲区的基本概念

文章目录动静态库自动化构建代码缓冲区原理实现具体实现动静态库首先要知道什么是链接:C程序中,并没有定义printf的函数实现,且在预编译中包含的stdio.h中也只有该函数的声明,而没有定义函数的实现系统把这些函数实现都被做到名为libc.so.6的库文件中去了,在没有特别指定时,gcc会到系统默认的搜索路径“/usr

JAVA面经整理(2)

一)解决哈希冲突的方法有哪些?哈希冲突指的是在哈希表中,不同的键值映射到了相同的哈希桶,也就是数组索引,导致键值对的冲突1)设立合适的哈希函数:通过哈希函数计算出来的地址要均匀的分布在整个空间中2)负载因子调节:2.1)开放地址法:1)当发生哈希冲突时,如果哈希表中没有装满,说明哈希表中一定还有空余位置,那么可以把ke

热文推荐