C++继承和数组

C++ inheritance and arrays

本文关键字:数组 继承 C++      更新时间:2023-10-16

c++ 新手在这里

所以我正在检查类在 c++ 中是如何工作的,我写了这段代码:

class A{
   ...
}
class B: public A{
...
}
int main(void){
  A array[10];
}

C++ 中的继承与 Java 中的继承的工作方式相同吗?我可以在数组中添加 B 类型的对象吗?如果是,我该怎么做?简单地做array[0] = new B();是行不通

附言只是一个后续问题,有人可以给我看一个具有简单构造函数的类的对象数组的快速示例吗?出于某种原因,我对此有问题。如果它有点复杂,我会发布另一个问题。提前致谢

在 Java 中,类类型的变量始终是对对象的引用。 即

A a = new A();
A a2 = a; // now a and a2 represent the same object
a.x = 12; // now print(a2.x) will also output 12

new A()将在堆(可以动态分配的内存区域(上创建实际对象,并返回它的内存地址。 aa2实际上(内部(仅包含该地址。

与包含实际值的整型变量不同,因此:

int a = 1;
int a2 = a;
a = 3;
// now a2 will still be 1

在C++对象被放置在堆栈上,方式与整型相同(除非使用引用或指针(。所以:

class A {
public:
   int x;
};
A a;
A a2;
a.x = 1;
a2 = a; // actually calls a2.operator=(a) which is implicitly defined, and assigns all data members (here only int x) the values from the other A
a.x = 2;
std::cout << a2.x << std::end; // will output 1

对于数组来说仍然如此:如果你声明一个数组A as[10],就像在堆栈上分配的一系列 10 A 对象一样。

遗产

如果你有

class A {
public:
    int x;
};
class B : public A {
public:
    int y;
};
A a;
a.x = 1;
B b;
b.x = 2;
b.y = 500;
// and then:
a = b; // now a.x == 2, but a holds no information about the y value
// with arrays it is the same:
A as[2];
as[0] = b; // now as[0].x == 2, --

执行a = b仅将b的值从其超类复制到a 中。

引用

A a;
a.x = 1;
A& a_ref = a;

现在a_ref是对a的引用与Java不同,不能使引用指向另一个对象。相反,这样做a_ref = a2会产生与a = a2相同的效果

a.x = 2
std::cout << a_ref.x << std::endl; // now outputs 2

此外,与Java不同,只要a_ref存在,a就必须存在,否则a_ref无效,访问它会使程序崩溃。在 Java 中,对象在堆上分配,并且仅在不存在指向它的引用时才解除分配(这称为垃圾回收(。

B b;
A& a_ref2 = b;
// now a_ref2 is a reference to b.
// (aka B has been downcasted)
// to access b.y from a_ref2, you could do:
int the_y = static_cast<B&>(a_ref2).y

不建议使用此方法(静态上转换(,仅当您确定a_ref2指向B对象时才有效。否则,它会填充段错误/崩溃。

如果A是多态的(见下文(,则可以改用dynamic_cast<B&>(a_ref2)(仍然不推荐(。如果a_ref2不是B,它会检测错误并引发异常。

多态性

class A {
public:
    virtual int get_v() { return 1; }
    int get() { return 1; }
    int get_a() { return 3; }
};
class B : public A {
public:
    int get_v() override { return 2; } // 'override' is not needed, and only works in C++11
    int get() { return 2; }
};
B b;
A& a_ref = b;
b.get_v(); // returns 2
b.get(); // returns 2
b.get_a(); // returns 3, by inheritance
a_ref.get_v(); // returns 2, because get_v is a virtual function.

因为虚函数 A 和 B 是多态类。在编译时不知道这会调用A::get_v还是B::get_v,因为a_refA&类型。相反,要调用的函数是在运行时决定的,具体取决于a_ref指向的内容。在Java中,所有函数都是这样的。

a_ref.get(); // returns 1.

因为get()不是多态的,所以它调用Aget()函数,因为a_refA&类型。

a_ref.get_a(); // returns 3, by inheritance

指针

指针类似于引用,但级别较低。访问引用的方式与访问实际对象(a_ref.xb.x(相同。指针变量是地址。与引用不同,它们可以在初始赋值后指向另一个对象:

B b; // same classes A and B as before
A* a_ptr = &b; // a is now a pointer to b.
// The type A* means "pointer to B". &b means "address of b".
// Polymorphism works the same:
a_ptr->get_v(); // returns 2
a_ptr->get(); // returns 1.
a_ptr->get_a(); // returns 3.

动态内存分配还会返回指针:

A* a_ptr = new B(); // a_ptr is now a pointer to a B allocated on the heap
...
delete a_ptr; // must be done to deallocate the B, otherwise there will be a memory leak.

因为a_ptr是类型A*(而不是B*(,所以多态类的析构函数应该是虚拟的:

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

否则只有A::~A会被召唤。

因此,在您的情况下,您可以执行以下操作:

A* array[10];
array[0] = new B();
array[0]->get_v();
delete array[0];

但是数组中所有尚未初始化的指针都将无效。 即 array[1]->get_v()delete array[1]将是一个错误。

然后array将是一个指向类型为 AA 的子类的指针数组。

您还可以像这样动态分配 A 数组:

A* array = new[10] A; // array is now a pointer to an array
array[0].x = 1;
delete[] array; // Deallocates as many items as where allocated

但这和以前一样做A as[10]一样,只是在堆栈上。这些将是A对象,执行array[0] = b只会从b复制b.x

unique_ptr

一个好的解决方案可能是使用 STL 中的std::unique_ptr。它是指针的包装器,因此没有两个unique_ptr可以指向同一项目。(因为禁止复制unique_ptr等(:

#include <memory>
// needed for std::unique_ptr
std::unique_ptr<A> array[10];
array[0].reset( new B() ); // needed to assign a value to it
array[0]->get_v();

按预期工作。尚未赋值的array元素默认初始化为零。访问它们会引发异常而不是段错误等。

不能为项分配=(因为语义不同(。相反,reset分配指针。如果它之前有另一个指针,那么第一个delete那个指针。也不需要(或可能(delete array[0],当变量array超出范围时,unique_ptr会删除项目。

允许

多个指针指向同一对象的解决方案,以便仅在没有指针指向对象时才解除分配对象,也在 STL: shared_ptr 中。

数组构造函数

对于堆栈上的项目数组,例如

A array[10];

它将始终调用默认构造函数(没有参数(。没有办法将参数传递给它。

std::array可以复制初始化(即构造函数采用单个值:(

class A {
public:
    int x;
    A(int nx) : x(nx) {}
};
std::array<A, 3> ar = { 1, 2, 3 };
// or
std::array<A, 2> ar2 = { a, a2 }; // makes copies