0
点赞
收藏
分享

微信扫一扫

【科普】简述机器学习和深度学习及其相关的算法

纽二 2024-11-11 阅读 16

文章目录


前言:

一、继承

1、概念

  • 基类与派生类: 基类是一个已经定义好的类,包含了一些属性和行为。派生类是在基类的基础上进行扩展,可以添加新的属性和行为,或者重写基类的方法。
  • 派生类的定义: 在C++中,使用:运算符来定义一个派生类。
class 派生类名:[继承方式] 基类名{
    派生类新增加的成员
};

示例代码:

#include <iostream>
#include <string>

// 基类 Animal
class Animal {
public:
    // 基类的构造函数
    Animal(const std::string& name) : name_(name) {}

    // 基类的成员函数
    void eat() const {
        std::cout << name_ << " is eating." << std::endl;
    }

    // 基类的虚函数,用于后续的多态性
    virtual void sound() const {
        std::cout << "Some generic animal sound." << std::endl;
    }

    // 基类的析构函数(虚析构函数是良好的实践,尤其是当基类有虚函数时)
    virtual ~Animal() {}

private:
    std::string name_; // 基类的私有数据成员
};

// 派生类 Dog,继承自 Animal
class Dog : public Animal {
public:
    // 派生类的构造函数,调用基类的构造函数
    Dog(const std::string& name, const std::string& breed) 
        : Animal(name), breed_(breed) {}

    // 重写基类的虚函数
    void sound() const override {
        std::cout << name_ << " barks." << std::endl;
    }

    // 派生类特有的成员函数
    void fetch() const {
        std::cout << name_ << " is fetching the ball." << std::endl;
    }

private:
    std::string breed_; // 派生类的私有数据成员
};

int main() {
    // 创建 Dog 对象
    Dog myDog("Buddy", "Golden Retriever");

    // 调用派生类的成员函数
    myDog.fetch();

    // 调用基类的成员函数(通过派生类对象)
    myDog.eat();

    // 调用重写后的虚函数
    myDog.sound();

    // 基类的虚析构函数确保当派生类对象被销毁时,基类部分也被正确清理
    return 0;
}

2、继承类型

  • 公有继承: 在这种类型的继承中,基类的公有成员在派生类中仍然是公有的,而基类的保护成员在派生类中仍然是保护的。这是最常用的继承类型。
  • 私有继承: 当使用私有继承时,基类的所有公有成员和保护成员在派生类中都会变成私有的。这意味着派生类的对象不能直接访问这些成员,但派生类内部可以访问。
  • 保护继承: 保护继承与私有继承类似,但基类的公有成员在派生类中会变成保护的。这意味着派生类的对象不能直接访问这些成员,但派生类及其派生类可以访问。

3、继承中的构造函数与析构函数

3.1、构造函数

  • 创建派生类对象时,先调用基类的构造函数,再调用派生类的构造函数。
  • 派生类的构造函数,如果没有主动调用基类的构造函数,当创建派生类对象时,编译器会自动调用基类的默认构造函数。
  • 可以在派生类的初始化列表中调用基类的构造函数。

示例代码:

#include "stdafx.h"
using namespace std;

class Base
{
public:
    Base(int age) {
        m_age = age;
    }
private:
    int m_age;
};

class Derived : public Base
{
public:
    Derived(int age, int grade) : Base(age) {
        m_grade = grade;
    }

private:
    int m_grade;
};

int main()
{
    return 0;
}

3.2、析构函数

  • 派生类对象声明周期结束时,先调用基类的析构函数再调用派生类的析构函数。这种顺序确保了对象从派生类到基类的逐层销毁。

示例代码:

#include <iostream>

class Base {
public:
    Base() { std::cout << "Base constructor called" << std::endl; }
    virtual ~Base() { std::cout << "Base destructor called" << std::endl; } // 虚析构函数
};

class Derived : public Base {
public:
    Derived() { std::cout << "Derived constructor called" << std::endl; }
    ~Derived() { std::cout << "Derived destructor called" << std::endl; }
};

int main() {
    Base* basePtr = new Derived(); // 多态:基类指针指向派生类对象
    delete basePtr; // 调用的是 Derived 类的析构函数,然后是 Base 类的析构函数
    return 0;
}

4、成员隐藏

class Base {
public:
    void func() { std::cout << "Base func" << std::endl; }
};

class Derived : public Base {
public:
    void func() { std::cout << "Derived func" << std::endl; }
};

int main() {
    Derived d;
    d.func(); // 输出 "Derived func"
    return 0;
}

5、多重继承

5.1、定义

class Base1 {
public:
    void func1() { /* ... */ }
};

class Base2 {
public:
    void func2() { /* ... */ }
};

class Derived : public Base1, public Base2 {
public:
    void func3() { /* ... */ }
};

5.2、多继承带来的问题

  • 二义性问题: 如果多个基类有同名的成员函数或数据成员,子类在访问这些成员时可能会产生二义性。为了解决这个问题,C++提供了作用域解析运算符(::),允许子类明确指定要访问的基类成员。
  • 菱形继承问题: 当两个基类都继承自同一个更基础的类,并且一个子类同时继承这两个基类时,就形成了菱形继承结构。这可能导致基类成员在子类中有多个副本,从而引发数据不一致的问题。为了解决这个问题,C++引入了虚继承的概念。
  • 复杂性和维护难度: 多重继承增加了类的复杂性和维护难度。由于子类可能依赖于多个基类的实现细节,因此当基类发生变化时,子类可能也需要进行相应的修改。

示例:二义性问题

class Base
{
public:
    void show() { cout << "I am Base class" << endl; }
};

class Person
{
public:
    void show() { cout << "I am Person class" << endl; }
};

class Student : public Base, public Person
{
public:
    void show()
    {
        Person::show();
    }
};

int main()
{
    Student obj;
    obj.show();  // 输出结果 I am Person class
    return 0;
}

5.3、虚继承

class Base {
public:
    void func() { /* ... */ }
};

class Intermediate1 : virtual public Base {
    // ...
};

class Intermediate2 : virtual public Base {
    // ...
};

class Derived : public Intermediate1, public Intermediate2 {
    // 在这里,Base的func()函数只会有一个实例被调用
};
举报

相关推荐

0 条评论