说明如何通过基类创建派生类的对象(虚拟析构函数概念)

Explanation of creating objects of derived class by a base class (Virtual destructor concept)

本文关键字:虚拟 析构函数 对象 何通过 基类 创建 派生 说明      更新时间:2023-10-16

我有两个类:

class A{
private:
    int a;
public:
    void display()
    {
        cout<<"A: "<<a;
    }
    A()
    {
        a=10;
    }
};
class B: public  A
{
private:
    int b;
    public:
    void display1()
    {
        cout<<"B: "<<b;
    }
    B()
    {
        b=15;
    }
};

A *a= new BB *b = new B有什么区别?对象b可以访问两个类AB的成员,而对象a只能访问类A的成员。然而,在以下给出的虚拟析构函数示例中:没有虚拟构造函数,但虚拟析构函数或任何其他示例,它总是显示基类创建派生类的对象。为什么这会有用?当 obj a 只能访问class A的成员时,创建class B对象有什么需要?

我无法为此想出一个实际的例子。

我无法为此想出一个实际的例子。

它被称为多态性,它可以说是OOP最重要的方面。基类可以使用虚函数定义接口;派生类可以重写这些函数以提供它们喜欢的任何行为。用户可以与基类交互,而不了解派生类,并且仍然可以使用派生类的功能。

为了提供一个示例,只需更改基类以声明一个虚拟函数:

virtual void display() {cout << "An";}

并更改派生类以覆盖它,而不是声明具有不同名称的不相关函数:

void display() override {cout << "Bn";}

现在我们可以看到 A 类型的对象之间的区别:

A a;
a.display();   // prints A

以及类型 B 之一,即使通过指针或对 A 的引用访问:

B b;
A & a = b;
a.display();   // prints B

想象一下这个应用程序。您有一个形状类(基(和两个矩形和trangle类(派生(。如何从基类函数计算每个形状的面积。

class shape {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    //look this method is virtual and is implemented in derived classes
    virtual int area () 
      { return 0; }
};
class Rectangle: public shape  {
  public:
    int area ()
      { return width * height; }
};
class Triangle: public shape  {
  public:
    int area ()
      { return (width * height / 2); }
};

用法

shape* s1 = new Rectangle();
shape* s2 = new Triangle();
//set values accordingly

然后你可以调用area函数,看看哪些方法会调用......

s1->area(); //area method of rectangle class
s2->area(); // area method of tangle class 

希望你明白了。

这是一个从外部访问的问题。虽然a允许用户只访问A的界面,但b允许用户也访问B的界面。你似乎已经明白这部分了。

你的第三个问题需要另一个比较:A *a = new B;A *a = new A;有什么区别?这里的区别在于,在第一个示例中,A 中的所有虚拟方法都被 B 的"替换"。这称为专业化。虽然你使用超类A更通用的接口,运行时的实现是B虚方法的。由于这些方法通常依赖于B的数据结构,因此必须实例化类B的对象。

A* a = new B;

以及

B* b = new B;

在堆上创建一个对象。在第一种情况下,可以通过指针a访问A中定义的函数。如果A有任何virtual函数并且它们是在B中实现的,那么在a上调用这些函数最终将调用B中的函数。a上的任何非virtual函数调用都将调用 A 中定义的函数。

在第二种情况下,可以通过指针b访问B中定义的函数以及A中定义的函数。

在您的情况下,您可以使用:

a->display();

以及

b->display();

您可以使用

b->display1();

但你不能使用

a->display1();

如果将display()display1()替换为虚拟函数,例如:

class A
{
   public:
      virtual display() { ... }
};
class B : public A 
 {
   public:
      virtual display() { ... }
};

然后,呼叫

a->display();

最终会打电话给B::display().