c++中继承多态virtual和override

目录

virtual:

易错点:

未声明虚函数:

忘记使用 override 关键字:

内存泄漏:

基类指针不指向任何对象:

访问权限问题:

不正确的类设计:

不正确的对象切片:

混淆 virtual 和 static 成员函数:

多重继承的二义性:

override:

继承(Inheritance):

多态(Polymorphism):

virtual 关键字:

override 关键字:


virtual:

C++中,继承和多态通常与虚函数(virtual)一起使用,以实现运行时多态性。以下是有关继承、多态和虚函数的更详细说明:

  1. 继承

    • 继承是一种机制,允许你创建一个新的类(派生类/子类),该类可以继承另一个类(基类/父类)的属性和方法。
    • 派生类可以访问基类的公有和受保护成员,但不能访问基类的私有成员。
  2. 多态

    • 多态是一种特性,允许不同对象对相同的消息(函数调用)做出不同的响应。
    • 多态可以通过函数重载和虚函数来实现。
  3. 虚函数

    • 虚函数是在基类中声明的函数,可以在派生类中被重写。
    • 声明一个函数为虚函数需要在函数声明前加上 virtual 关键字,例如:virtual void someFunction();
    • 当通过基类指针或引用调用虚函数时,实际执行的是派生类中的版本,而不是基类中的版本。这个过程被称为动态绑定,它实现了多态性。

示例:

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

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

int main() {
    Base* ptr = new Derived();
    ptr->print(); // 调用 Derived 类中的 print() 函数
    delete ptr;
    return 0;
}

在上面的示例中,Base 类中的 print 函数被声明为虚函数,而 Derived 类中重写了这个虚函数。当通过指向 Derived 对象的 Base 指针调用 print 函数时,会调用 Derived 类中的版本,实现了多态性。这是因为虚函数的调用在运行时动态绑定到正确的函数版本。

易错点:

当使用C++中的继承、多态和虚函数时,以下是每个点的更详细解释以及如何避免相关错误:

  1. 未声明虚函数

    • 错误说明:如果在基类中未将成员函数声明为虚函数,那么派生类中对该函数的重写将不会触发动态绑定,这可能导致多态性无法正常工作。
  2. 解决方法:确保在基类中需要多态性的成员函数前使用 virtual 关键字进行声明。例如:
    class Base {
    public:
        virtual void myFunction() {
            // ...
        }
    };
    

忘记使用 override 关键字

  • 错误说明:在派生类中重写虚函数时,使用 override 关键字可以帮助编译器检查是否正确地重写了基类函数。如果忘记使用它,编译器无法提供此种检查。
  • 解决方法:在派生类中重写虚函数时,使用 override 关键字,这样编译器可以检查错误:
    class Derived : public Base {
    public:
        void myFunction() override {
            // ...
        }
    };
    

  1. 内存泄漏

    • 错误说明:内存泄漏是未释放动态分配的内存的情况。特别是在使用指向派生类对象的基类指针时,容易忘记释放内存。
    • 解决方法:使用 delete 来手动释放内存是一种方法,但更好的做法是使用智能指针(如 std::shared_ptrstd::unique_ptr)来管理内存。这些智能指针会自动处理内存释放,减少内存泄漏的风险。
  2. 基类指针不指向任何对象

    • 错误说明:如果将基类指针设置为未初始化或空指针,然后尝试调用虚函数,会导致未定义行为。
    • 解决方法:始终确保基类指针指向有效的派生类对象,或者在调用虚函数之前检查指针是否为 nullptr。避免未初始化的指针

 

Base* ptr = nullptr; // 初始化为 nullptr
// ...
if (ptr != nullptr) {
    ptr->myFunction(); // 在调用前检查指针是否为 nullptr
}
  1. 访问权限问题

    • 错误说明:派生类尝试访问基类的私有成员,这是不允许的,因为私有成员只能在基类内部访问。
    • 解决方法:确保派生类只访问基类中的公有或受保护成员,或者使用友元关系来解决权限问题。
  2. 不正确的类设计

    • 错误说明:不良的类设计可能导致难以维护和理解的代码,或者使多态性无法正确工作。
    • 解决方法:在设计类层次结构时,仔细考虑每个类的责任和关系,确保清晰的抽象和继承关系。使用合理的类层次结构来避免混乱和不必要的复杂性。
  3. 不正确的对象切片

    • 错误说明:将派生类对象赋值给基类对象会导致对象切片,丢失派生类的信息。这可能导致意外行为和数据丢失。
    • 解决方法:在处理派生类对象时,始终使用基类指针或引用,以避免对象切片。不要试图将派生类对象隐式转换为基类对象。
Base baseObj = derivedObj; // 对象切片,避免这种情况

 

  1. 混淆 virtualstatic 成员函数:

    • 错误说明:混淆虚函数和静态成员函数是一种常见的错误。静态成员函数与类关联,而虚函数与对象关联。
    • 解决方法:理解 virtual 成员函数是动态绑定的,而 static 成员函数是与类关联而不是与对象关联的。确保在适当的情况下使用每种类型的函数。
  2. 多重继承的二义性

    • 错误说明:在多重继承中,如果两个基类具有相同名称的成员,可能会导致二义性,编译器无法确定应该使用哪个成员。
    • 解决方法:使用作用域解析运算符(::)来明确指定要使用的基类成员,或者使用虚继承来解决二义性问题。虚继承用于在多重继承中解决菱形继承问题,以避免二义性。

override:

在C++中,继承、多态和 override 关键字是面向对象编程中的重要概念,它们一起用于创建和使用基类和派生类之间的关系。以下是有关这些概念的详细解释:

  1. 继承(Inheritance)

    • 继承是一种面向对象编程的机制,允许一个类(子类/派生类)从另一个类(父类/基类)继承属性和方法。
    • 子类可以继承父类的成员变量和成员函数,以及它们的访问权限。
      class Base {
      public:
          int baseVar;
          void baseFunction() {
              // ...
          }
      };
      
      class Derived : public Base {
      public:
          // Derived 继承了 baseVar 和 baseFunction
          // 可以访问它们并添加新的成员
          void derivedFunction() {
              // ...
          }
      };
      

多态(Polymorphism)

  • 多态是一种特性,允许不同对象对相同的消息(函数调用)做出不同的响应。
  • 多态可以通过虚函数和函数重载来实现。

 

class Shape {
public:
    virtual void draw() {
        // 基类虚函数
    }
};

class Circle : public Shape {
public:
    void draw() override {
        // 派生类重写了基类虚函数
    }
};

void drawShape(Shape* shape) {
    shape->draw(); // 调用虚函数,根据对象类型执行正确的函数
}

virtual 关键字

  • virtual 是用于声明虚函数的关键字。
  • 虚函数是在基类中声明的函数,可以在派生类中被重写。
  • 当通过基类指针或引用调用虚函数时,实际执行的是派生类中的版本,这实现了运行时多态性。、
class Base {
public:
    virtual void myFunction() {
        // 基类虚函数
    }
};

override 关键字

  • override 是 C++11 引入的关键字,用于明确指示一个函数是派生类中对基类虚函数的重写。
  • 使用 override 可以帮助编译器检查是否正确地重写了基类的虚函数,防止错误。
    class Derived : public Base {
    public:
        void myFunction() override {
            // 派生类重写了基类虚函数
        }
    };
    

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