C++ 三大特性(封装、继承、多态)

1.封装(Encapsulation)

C++封装就是将数据和操作包装成一个单独的实体(类)中,并通过控制访问权限隐藏内部实现细节。

封装就像把一个物品放进一个箱子里面,箱子外部的人只能通过箱子上的接口来与物品进行交互,而无法直接触及物品的内部细节。

1.创建一个简单的类 

#include <iostream>
#include <string>

using namespace std;

class Student {
public:
    string name;
    int age;
    string major;

    void displayInfo() const {
        cout << "Name: " << name << ", Age: " << age << ", Major: " << major << endl;
    }
};

int main() {
    Student student;
    student.name = "John";
    student.age = 20;
    student.major = "Computer Science";

    student.displayInfo(); // 输出:Name: John, Age: 20, Major: Computer Science

    return 0;
}

上面代码就是将属性和行为封装到了一个类中,可以通过对类的调用进行使用。

2.C++ 类访问修饰符

访问修饰符是一种用于控制类成员(变量和函数)可访问性的关键字。在C++中,有三种访问修饰符 

public:
  • 公有成员可以在类的内部和外部访问。
  • 可以通过对象或类的实例访问公有成员。
  • 公有成员对于类的用户是可见的。
  • 默认情况下,类的成员是公有的。
class MyClass {
public:
    int publicVar;  // 公有变量
    void publicFunc() { // 公有函数
        // 函数实现
    }
};

int main() {
    MyClass obj;
    obj.publicVar = 10;  // 访问公有变量
    obj.publicFunc();   // 调用公有函数
    return 0;
}
protected:
  • 受保护的成员可以在类的内部和派生类中访问。
  • 可以通过派生类的对象或指针访问受保护的成员,无法通过类的实例访问。
  • 受保护的成员对于类的用户是不可见的。
class MyBaseClass {
protected:
    int protectedVar;  // 受保护变量
    void protectedFunc() { // 受保护函数
        // 函数实现
    }
};

class MyDerivedClass : public MyBaseClass {
public:
    void accessProtected() {
        protectedVar = 10;  // 访问受保护变量
        protectedFunc();   // 调用受保护函数
    }
};

int main() {
    MyDerivedClass obj;
    obj.accessProtected();  // 调用派生类的函数来访问受保护成员
    return 0;
}
private:
  • 私有成员只能在类的内部访问。
  • 私有成员对于类的派生类和类的用户都是不可见的。
class MyClass {
private:
    int privateVar;  // 私有变量
    void privateFunc() { // 私有函数
        // 函数实现
    }
public:
    void accessPrivate() {
        privateVar = 10;  // 访问私有变量
        privateFunc();   // 调用私有函数
    }
};

int main() {
    MyClass obj;
    obj.accessPrivate();  // 调用公有函数来访问私有成员
    return 0;
}

注意:访问修饰符只对类的成员起作用,不影响类的对象的访问权限。

3.继承(Inheritance): 

当我们谈到继承时,可以将其比喻为家族关系。想象一下,有一个大家族,由祖父母、父母和子女组成。祖父母是这个家族的根源,他们有一些特定的特征和行为。父母是祖父母的孩子,他们继承了一些祖父母的特征,但也有一些自己的特征。子女是父母的孩子,他们继承了祖父母和父母的特征,并可以有自己独特的特征。

类的继承也是类似的概念。一个类可以继承另一个类的属性和行为,并可以添加自己的属性和行为。这个被继承的类称为父类或基类,而继承这个父类的类称为子类或派生类。

继承的好处在于代码的重用和扩展。通过继承,子类可以继承父类的特性,不需要从头开始编写相同的代码。子类可以重用父类的方法和属性,并且可以添加自己特有的方法和属性。这使得代码更加模块化和易于维护。

假设我们有一个基类叫做"车辆",它有一些通用的特征和行为,比如品牌、颜色和驾驶方法。现在,我们可以派生出不同类型的车辆,比如"轿车"和"卡车"作为子类,它们继承了"车辆"类的特征和行为,并可以具有自己特定的特征和行为。

"轿车"子类可以有特定的属性,比如座位容量和车型(如轿跑车或家庭轿车),同时还可以继承"车辆"类的共同属性,比如品牌和颜色。此外,"轿车"类可以定义自己的行为,比如加速、制动和打开车门。

继承的主要概念:

  1. 公有继承(public inheritance):子类继承父类的公有成员和保护成员,但不继承私有成员。继承后,父类的公有成员在子类中仍然是公有的,保护成员在子类中仍然是保护的。
  2. 保护继承(protected inheritance):子类继承父类的保护成员和私有成员,但不继承公有成员。继承后,父类的保护成员在子类中变为保护的,私有成员在子类中仍然是私有的。
  3. 私有继承(private inheritance):子类继承父类的所有成员,但都变为私有成员。在私有继承中,父类的公有和保护成员在子类中都变为私有的。
class Animal {
public:
    void eat() {
        cout << "Animal is eating." << endl;
    }
};

class Dog : public Animal {
public:
    void bark() {
        cout << "Dog is barking." << endl;
    }
};

int main() {
    Dog dog;
    dog.eat();  // 调用从Animal继承的成员函数
    dog.bark(); // 调用Dog自己的成员函数
    return 0;
}

4.多态(Polymorphism)

多态就是多种形态,指的是同一个方法或函数可以在不同的对象上产生不同的行为。

多态性的好处在于增强了代码的灵活性和可扩展性。通过多态,我们可以编写通用的代码,处理不同类型的对象,而无需为每个对象编写特定的代码。这提高了代码的可重用性和可维护性,并使程序更容易扩展和修改。

想象你有一个车的基类(Car),这个基类有一个共同的方法叫作"drive"(驾驶)。现在,你有两个具体的车类,一个是小轿车类(Sedan),另一个是卡车类(Truck),它们都继承自车的基类。

当你调用小轿车的"drive"方法时,它会执行小轿车的特定驾驶行为,例如加速并平稳地行驶在道路上。

而当你调用卡车的"drive"方法时,它会执行卡车的特定驾驶行为,例如启动大型引擎、慢慢启动并承载重物。

尽管你使用了相同的方法名"drive",但在不同的车对象上调用时,会产生不同的行为。这就是多态的体现,同一个方法根据对象的实际类型,产生不同的行为。

多态的实现方式主要有两种:静态多态和动态多态。

1.静态多态(Static Polymorphism):

也称为编译时多态或早期绑定。在编译时期,根据函数的参数类型或重载函数的签名,确定要调用的具体函数。这种多态是通过函数重载(function overloading)和运算符重载(operator overloading)实现的。

#include <iostream>
using namespace std;

class Shape {
public:
    virtual void draw() {
        cout << "绘制形状" << endl;
    }
};

class Circle : public Shape {
public:
    void draw() override {
        cout << "绘制圆形" << endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() override {
        cout << "绘制矩形" << endl;
    }
};

int main() {
    Shape* shape1 = new Circle();
    Shape* shape2 = new Rectangle();

    shape1->draw();  // 输出:绘制圆形
    shape2->draw();  // 输出:绘制矩形

    delete shape1;
    delete shape2;

    return 0;
}

无论是调用shape1->draw()还是shape2->draw(),都会根据静态类型调用基类Shape的draw方法。这就是静态多态性的特点,方法的调用在编译时确定,不会根据对象的实际类型在运行时动态确定。 

2.动态多态(Dynamic Polymorphism):

也称为运行时多态或晚期绑定。在运行时期,根据对象的实际类型,确定要调用的具体方法。这种多态是通过继承和虚函数(virtual function)实现的。在基类中声明虚函数,并在派生类中进行重写(override),从而实现多态性。

#include <iostream>
using namespace std;

class Car {
public:
    virtual void drive() {
        cout << "车辆正在行驶..." << endl;
    }
};

class Sedan : public Car {
public:
    void drive() override {
        cout << "小轿车在平稳地行驶。" << endl;
    }
};

class Truck : public Car {
public:
    void drive() override {
        cout << "卡车正在承载重物行驶。" << endl;
    }
};

int main() {
    Car* car1 = new Sedan();
    Car* car2 = new Truck();

    car1->drive();  // 输出:小轿车在平稳地行驶。
    car2->drive();  // 输出:卡车正在承载重物行驶。

    delete car1;
    delete car2;

    return 0;
}

当调用car1->drive()时,根据car1指针所指向的对象是Sedan,将调用Sedan类中的drive方法,输出"小轿车在平稳地行驶。"。

同样地,当调用car2->drive()时,根据car2指针所指向的对象是Truck,将调用Truck类中的drive方法,输出"卡车正在承载重物行驶。"。

这就是动态多态性的特点,方法的调用在运行时根据对象的实际类型确定,而不是在编译时确定。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值