面向过程:将问题分解成一个个详细的步骤,然后通过函数实现每一个步骤,并依次调用
特点:
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;
}