C++入门篇----封装,继承,多态

在大部分面向对象开发的编程语言中都有封装,继承,多态的三个特性。不管是java,python,还是C++。

一、什么是封装

官方解释:封装的意义在于将属性和行为(数据和操作数据的函数)作为一个整体,表现生活中的事物,同时保护数据成员不被类以外的程序直接访问或修改,只能通过提供的公共接口访问。

结合生活例子:想象一个闹钟。闹钟的内部有电路、电池、发声装置等。我们不关心闹钟是如何工作的,我们只关心它的功能:设置时间、响铃等。这就是封装。我们只看到闹钟给我们提供的接口(设置时间、响铃等),而其内部的具体实现细节被隐藏了。

class AlarmClock
 {  
private:  
    int hour;  
    int minute;  
public:  
    void setTime(int h, int m) { hour = h; minute = m; }  
    void ring() { std::cout << "闹钟响了!" << std::endl; }  
};

二、什么是继承 

官方解释:C++继承是面向对象编程中的一个重要概念,它使得一个类可以从另一个类派生出来,从而继承了父类的属性和方法。继承提供了代码重用和多态性支持,使得程序更加灵活和可维护。

结合生活例子:想象一个家庭,家庭成员之间存在着某种关系,这种关系可以被视为一种继承。在这个家庭中,父亲是基类,而儿子和女儿是派生类,分别从父亲继承了一些样貌和行为。

class Father {  
public:  
    string name;  
    int age;  
    string occupation;  
    void work()
    { 
     cout << "Person is working." << endl;
    }  
    void earnMoney()
    { 
     cout << "Person is earning money." << endl;
    }  
    void takeCareOfFamily() 
    { 
      cout << "Person is taking care of family." << endl;
    }  
};  
  
class Son : public Person {  
public:  
    void playGuitar() 
    { 
     cout << "Son is playing guitar." << endl; 
    }  
};  
  
class Daughter : public Person {  
public:  
    void dance() 
    {
     cout << "Daughter is dancing." << endl;
    }  
};

在C++中,继承通过使用冒号(:)关键字来实现。当一个类从另一个类派生时,子类会自动继承父类的所有公有和保护成员。子类可以拥有自己的属性和方法,也可以重写父类的方法。

C++提供了两种继承方式:公有继承(public)和私有继承(private)。

  • 公有继承(public):子类具有访问父类的公有成员和保护成员权限。
  • 私有继承:子类不能访问父类的公有成员和保护成员权限。

 public:public成员在类外部可访问。这意味着任何包含该类对象的代码都可以访问public成员。

// 声明一个公有类  
class MyClass {  
public: // 公有成员在类外部可访问  
    // 公有构造函数  
    MyClass() {  
        // 初始化成员变量  
        x = 0;  
        y = 0;  
    }  
    // 公有成员函数  
    void setValues(int a, int b) {  
        x = a;  
        y = b;  
    }  
    // 公有成员函数  
    void printValues() {  
        cout << "x: " << x << ", y: " << y << endl;  
    }    
};
class my :public MyClass
{

void manage()
{
 cout << "Managing stock: " << endl;  
 cout << "Managing salary: "  << endl;  
}

}

private:private成员只能在类内部访问。这意味着只有类的成员函数可以访问private成员,而类的对象或派生类无法直接访问private成员。

// 声明一个私有类  
class PrivateClass {  
private: // 私有成员在类外部不可访问  
    int privateVar; // 私有成员变量  
};  
  
// 声明一个公有类,继承自PrivateClass  
class PublicClass : public PrivateClass {  
public:  
    void display() {  
        cout << "privateVar: " << privateVar << endl; // 错误!PrivateClass中的private成员不能被PublicClass继承访问  
    }  
};  
  
int main() {  
    PublicClass myObject; // 创建一个PublicClass对象  
    myObject.display(); // 尝试访问PrivateClass中的private成员,会导致编译错误  
    return 0;  
}

 我们有一个名为PrivateClass的私有类,其中包含一个私有成员变量privateVar。然后我们有一个名为PublicClass的公有类,它试图继承自PrivateClass。在PublicClass中,PrivateClass中的privateVar成员是不允许访问的,因为privateVar是PrivateClass的私有成员,不能被子类继承访问。

这就好比有一个小木箱,上面写着“私人物品”,你不能打开这个木箱,因为你没有权限。同样地,公有类PublicClass也不能打开私有类PrivateClass的“私人物品”箱子。通过这样的访问控制,我们可以确保数据的封装和安全性

 protected关键字:protected成员在类外部不可访问,但在派生类中可访问。这意味着只有类的成员函数和派生类可以访问protected成员,而类的对象无法直接访问protected成员。

// 声明一个保护类  
class Family {  
protected: // 保护成员在类外部不可访问,但在派生类中可访问  
    string name; // 保护成员变量,表示家庭名称  
    int members; // 保护成员变量,表示家庭成员数量  
public: // 公有成员在类外部可访问  
    Family()
    {  
        name = "";  
        members = 0;  
    }  
    
};  
  
class BigFamily : public Family {  
public: // 公有成员在类外部可访问  
    void describe() 
    { // 描述家庭成员  
        cout << "In our family, we have " << members << " members. They are my grandpa, my grandma, my dad, my mom, my uncle, my aunt and me." << endl;  
    }  
};  
  
int main() {  
    BigFamily myBigFamily; // 创建一个BigFamily对象  
    myBigFamily.name = "Wang"; // 设置家庭名称  
    myBigFamily.members = 7; // 设置家庭成员数量  
    myBigFamily.describe(); // 描述家庭成员  
    return 0;  
}

这个例子中,我们有一个Family类,它表示一个家庭。家庭有一些保护成员,比如name和members,这些成员在类外部不可访问,但在派生类中可访问。

我们还定义了一个BigFamily类,它继承自Family类。在BigFamily类中,我们可以访问Family类的保护成员name和members。在main函数中,我们创建了一个BigFamily对象,并对其公有和保护成员进行了操作。 

三、什么是多态

多态性可以简单理解为“多种形态”。是指允许一个接口被多种形态实现,多态性是面向对象程序设计中的一个重要特性,它允许我们以统一的方式处理不同的数据类型。

比如说,你有一张画,这张画上可以画一个动物,也可以画一个植物,还可以画一个人,或者任何其他的东西。这就是多态性。

多态性可以通过虚函数和纯虚函数来实现。

1.虚函数:在基类中声明为virtual的函数。如果基类的某个函数前有virtual关键字,则派生类可以重写这个函数,此时,这个函数被称为虚函数。

class Animal {  
public:  
    virtual void makeSound() {  
        cout << "The animal makes a sound" << endl;  
    }  
};
class Derived : public Animal {  
public:  
    void makeSound() { cout << "Derived foo" << endl; }  
};

 在上面的例子中,Animal作为基类,Derived作为派生类。Animal类中定义了一个以virtual的虚构函数,而Derived 继承了Animal类的makeSound函数,并重新定义函数里面的内容。

结合生活例子讲解,动物都有叫声,但是猫叫和老虎叫声又是不一样的。所以需要一个虚构函数来定义一个叫声的总函数,之后猫、老虎又各自定义自己的叫声。

2.纯虚函数

纯虚函数是C++中一个特殊的函数,它是在基类中声明为virtual,但没有实现(即没有花括号)的函数。

// 定义一个基类 "水果"  
class 水果 {  
public:  
    // 声明一个纯虚函数 "味道"  
    virtual void 味道() = 0; // 纯虚函数,没有默认实现  
};  
  
// 定义一个派生类 "苹果"  
class 苹果 : public 水果 {  
public:  
    // 实现基类中的纯虚函数 "味道"  
    void 味道() {  
        cout << "苹果的味道是甜的。" << endl;  
    }  
};  
  
// 定义一个派生类 "香蕉"  
class 香蕉 : public 水果 {  
public:  
    // 实现基类中的纯虚函数 "味道"  
    void 味道() {  
        cout << "香蕉的味道是香的。" << endl;  
    }  
};  
  
int main() {  
    // 创建一个基类指针,指向一个 "苹果" 对象  
    水果* fruitPtr = new 苹果();  
    // 通过基类指针调用纯虚函数 "味道",输出 "苹果的味道是甜的。"  
    fruitPtr->味道();  
    delete fruitPtr; // 释放内存  
  
    // 创建一个基类指针,指向一个 "香蕉" 对象  
    fruitPtr = new 香蕉();  
    // 通过基类指针调用纯虚函数 "味道",输出 "香蕉的味道是香的。"  
    fruitPtr->味道();  
    delete fruitPtr; // 释放内存  
  
    return 0;  
}

 为了更好地理解这个概念,我们可以举一个生活中的例子。想象一下,我们有一个抽象类“水果”,它包含一个纯虚函数“味道”。这个纯虚函数表示水果的味道,但是在抽象类中并没有给出具体的实现。如果我们尝试实例化这个抽象类,就会遇到一个问题:我们不知道这个水果的味道是什么。

因此,实例化抽象类是不被允许的。相反,我们可以创建一些派生类,如“苹果”、“香蕉”等,并为它们实现“味道”函数。这样,当我们需要一个水果对象时,就可以创建一个“苹果”或“香蕉”对象,并调用它们的“味道”函数。这样,我们就可以避免出现无法实例化抽象类的问题。

其他注意事项

  • 构造函数和析构函数不能被声明为虚函数,因为虚函数是在运行时确定的,而构造函数在编译时就已经确定。
  • 多态性是在不同继承关系的类对象中,去调用同一函数时产生不同的行为。例如,学生和老师都有人买票的行为,但是学生半价,老师全价,这就是多态。
  • 在实现多态时,必须通过基类的指针或引用调用虚函数,且被调用的函数必须是虚函数,派生类必须对基类的虚函数进行重写。

 

你可能感兴趣的:(c++,开发语言)