面向对象编程是一种程序设计范式,它将真实世界的概念抽象为对象,并通过对象之间的交互来实现程序功能。C++是一种支持面向对象编程的编程语言,其中类和对象是面向对象编程的核心概念。
一、类和对象的概念
类是一种抽象数据类型,它描述了一组具有相同特征和行为的对象。类定义了对象的属性和方法。对象是类的一个实例,它具有类定义的所有属性和方法。例如,人类可以被描述为一个类,而每个人则是这个类的一个对象。
C++中定义类的语法如下:
class className { public: // 属性和方法 }
其中,className是类的名称,public表示该类的属性和方法可以被其他类访问。
定义类的属性和方法类似于定义变量和函数:
class Person { public: string name; int age; void sayHello() { cout << "Hello, my name is " << name << ", I'm " << age << " years old." << endl; } };
上面的代码定义了一个Person类,其中包含了name和age两个属性,以及一个sayHello()方法。这个方法用于输出“Hello, my name is xxx, I'm xxx years old.”。
声明一个对象的语法为:
className objectName;
其中,className是类名称,objectName是对象名称。例如,我们可以声明一个Person对象:
Person p1;
这个对象p1将具有Person类定义的所有属性和方法。
二、类的访问修饰符
C++中,类的访问修饰符用于控制类的属性和方法的访问级别。C++中有三种访问修饰符,分别是public、private和protected。它们的区别如下:
- public属性和方法可以被任何类访问。
- private属性和方法只能被本类中的方法访问,不能被其他类访问。
- protected属性和方法可以在本类和子类中访问,但不能在其他类中直接访问。
下面是示例代码,演示使用不同的访问修饰符:
class Person { public: string name; // public属性 void sayHello() { // public方法 cout << "Hello, my name is " << name << endl; } private: int age; // private属性 void setAge(int a) {// private方法 age = a; } protected: string address; // protected属性 }; class Student : public Person { public: void setAddress(string a) { address = a; // 可以访问父类的protected属性 } }; int main() { Person p1; p1.name = "Jane"; p1.sayHello(); // p1.age = 20; // 错误:不能访问private属性 // p1.setAge(20); // 错误:不能访问private方法 Student s1; s1.setAddress("Beijing"); // s1.age = 20; // 错误:不能访问父类的private属性 // s1.setAge(20); // 错误:不能访问父类的private方法 return 0; }
上面的代码演示了Person类和Student类的定义,以及访问修饰符的使用。在Main函数中,我们可以看到,公共属性和方法可以在任何地方访问,私有属性和方法只能在本类中访问,而受保护属性和方法可以在本类和子类中访问。
三、构造函数和析构函数
构造函数和析构函数是面向对象编程中的重要概念,它们分别用于创建和销毁对象。
构造函数是一个特殊的方法,用于在创建对象时初始化对象的属性。C++中的构造函数名称与类名相同,在定义过程中没有返回值类型,例如:
class Person { public: Person(string n, int a) { // 构造函数 name = n; age = a; } void sayHello() { cout << "Hello, my name is " << name << ", I'm " << age << " years old." << endl; } private: string name; int age; };
上面的代码定义了一个Person类,其中有一个构造函数,用于在创建Person对象时初始化对象的属性。构造函数的参数是待初始化的属性值。
类似的,析构函数也是一个特殊的方法,用于在销毁对象时释放对象的资源。C++中的析构函数名称与类名相同,但在名称前面加上一个波浪线(~),例如:
class Person { public: Person(string n, int a) { name = n; age = a; } ~Person() { // 析构函数 cout << "Person object is destroyed." << endl; } void sayHello() { cout << "Hello, my name is " << name << ", I'm " << age << " years old." << endl; } private: string name; int age; };
在上面的代码中,析构函数用于在销毁Person对象时输出一条消息。
四、static成员变量和方法
类的static成员变量和方法是属于整个类而不是某个对象的。static成员变量和方法可以在对象创建之前就存在,因此它们可以在没有对象的情况下直接访问。例如:
class Person { public: static int count; // 定义一个静态成员变量 Person(string n, int a) { name = n; age = a; count++; // 静态成员变量count加1 } ~Person() { count--; // 静态成员变量count减1 } static void getCount() { // 定义一个静态成员方法 cout << "count = " << count << endl; } private: string name; int age; }; int Person::count = 0; // 静态成员变量需要在类外进行初始化 int main() { Person p1("John", 20); Person::getCount(); // 静态方法可以通过类名来调用 Person p2("Jane", 22); Person::getCount(); Person p3("Mary", 25); Person::getCount(); return 0; }
上面的代码演示了如何定义和使用静态成员变量和方法。在Person类定义中,我们定义了一个静态成员变量count和一个静态方法getCount()。在Main函数中,我们创建了三个Person对象,每次创建对象都会使count加1。通过调用静态方法getCount(),我们可以输出count的值。
五、继承
继承是面向对象编程中的一个重要概念,它可以让一个类继承另一个类的属性和方法,从而避免代码重复。在C++中使用":"符号表示继承关系,例如:
class Student : public Person { // Student类继承自Person类 public: string school; void study() { cout << name << " is studying in " << school << endl; } }; int main() { Student s1; s1.name = "John"; s1.age = 20; s1.school = "MIT"; s1.sayHello(); s1.study(); return 0; }
在上面的代码中,我们创建了一个Student类,并让它继承自Person类。由于继承了Person类,Student类可以使用Person类中的属性和方法。在Main函数中,我们创建一个Student对象s1,并为它设置属性值。通过调用sayHello()和study()方法,我们可以输出一些信息。
六、多态
多态是C++中面向对象编程的重要概念,它指的是同一种行为具有多种不同的表现形式。多态性是面向对象程序设计的一个重要的特点,它可以提高程序的灵活性和可维护性。
C++中多态的实现方式有两种,分别是函数重载和虚函数。
函数重载是指在同一个类中,可以定义多个名称相同但参数类型和个数不同的函数。例如:
class Calculator { public: int add(int a, int b) { cout << "Addition of two integers: "; return a + b; } float add(float a, float b) { cout << "Addition of two floats: "; return a + b; } }; int main() { Calculator c1; cout << c1.add(3, 5) << endl; // 输出8 cout << c1.add(3.1f, 5.7f) << endl; // 输出8.8 return 0; }
在上面的代码中,我们定义了一个Calculator类,并在其中定义了两个名称相同但参数类型和个数不同的add()方法。在Main函数中,我们分别调用两个add()方法,并输出计算结果。由于参数类型和个数不同,因此C++可以识别出应该调用哪个add()方法。
虚函数是指在基类中定义一个虚函数,在派生类中可以对该虚函数进行重定义。虚函数的定义方式为,在函数前加上关键字virtual,例如:
class Shape { public: virtual float area() { return 0; } virtual float perimeter() { return 0; } }; class Rectangle : public Shape { public: Rectangle(float l, float w) { length = l; width = w; } float area() { return length * width; } float perimeter() { return 2 * (length + width); } private: float length; float width; }; class Circle : public Shape { public: Circle(float r) { radius = r; } float area() { return PI * radius * radius; } float perimeter() { return 2 * PI * radius; } private: float radius; const float PI = 3.1415926; }; int main() { Shape* s1; Rectangle r1(3, 4); Circle c1(2); s1 = &r1; cout << "Rectangle area: " << s1->area() << endl; cout << "Rectangle perimeter: " << s1->perimeter() << endl; s1 = &c1; cout << "Circle area: " << s1->area() << endl; cout << "Circle perimeter: " << s1->perimeter() << endl; return 0; }
在上面的代码中,我们定义了一个Shape类,并在其中定义了一个虚函数area()和perimeter()。在Rectangle和Circle类中,我们分别对这两个方法进行了重定义。在Main函数中,我们声明了一个Shape指针s1,指向一个Rectangle对象r1。然后我们调用了s1的area()和perimeter()方法,由于Shape类中的area()和perimeter()方法是虚函数,在运行时会根据对象的类型调用相应的方法,因此输出的结果分别是Rectangle类和Circle类中的方法返回值。这就是多态性的体现。