C++ 继承和数组

aka*_*kin 1 c++ arrays inheritance

C++新手在这里

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

class A{
   ...
}
class B: public A{
...
}
int main(void){
  A array[10];
}
Run Code Online (Sandbox Code Playgroud)

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

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

tml*_*len 7

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

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
Run Code Online (Sandbox Code Playgroud)

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

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

int a = 1;
int a2 = a;
a = 3;
// now a2 will still be 1
Run Code Online (Sandbox Code Playgroud)

在 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
Run Code Online (Sandbox Code Playgroud)

对于数组,这仍然是正确的:如果您声明一个数组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, --
Run Code Online (Sandbox Code Playgroud)

这样做a = b的副本只从值b从其超,成a

参考

A a;
a.x = 1;
A& a_ref = a;
Run Code Online (Sandbox Code Playgroud)

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

a.x = 2
std::cout << a_ref.x << std::endl; // now outputs 2
Run Code Online (Sandbox Code Playgroud)

也不同于Java,a只要a_ref存在就必须存在,否则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
Run Code Online (Sandbox Code Playgroud)

这(静态向上转换),不推荐,只有当你确定它a_ref2指向一个B对象时才有效。否则它会填充段错误/崩溃。

如果A是多态的(见下文),dynamic_cast<B&>(a_ref2)可以代替使用(仍然不推荐)。它检测错误 if a_ref2is not aB并抛出异常。

多态性

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.
Run Code Online (Sandbox Code Playgroud)

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

a_ref.get(); // returns 1.
Run Code Online (Sandbox Code Playgroud)

因为get()不是多态的,它调用Aget()函数,因为a_ref它的类型是A&

a_ref.get_a(); // returns 3, by inheritance
Run Code Online (Sandbox Code Playgroud)

指针

指针就像引用,但级别较低。您访问引用的方式与实际对象(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.
Run Code Online (Sandbox Code Playgroud)

动态内存分配也返回指针:

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.
Run Code Online (Sandbox Code Playgroud)

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

class A {
public:
    ...
    virtual ~A() { .... }
};
class B : public A {
public:
    ...
    ~B() override { .... }
};
Run Code Online (Sandbox Code Playgroud)

否则只会A::~A被调用。

所以在你的情况下,你可以这样做:

A* array[10];
array[0] = new B();

array[0]->get_v();
delete array[0];
Run Code Online (Sandbox Code Playgroud)

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

array然后将是一个指向类型对象的指针数组A,或A.

您还可以像这样动态分配 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
Run Code Online (Sandbox Code Playgroud)

但这A as[10]和之前做的一样,只是在栈上。这些将是A对象,并且 doarray[0] = b只会复制b.xfrom b

unique_ptr

一个好的解决方案可能是std::unique_ptr从 STL使用。它是一个指针的包装器,因此没有两个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();
Run Code Online (Sandbox Code Playgroud)

按预期工作。的元素array没有被分配一个值都默认初始化为零。访问它们会抛出异常而不是段错误等。

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

中的溶液,以允许指向同一个对象的多个指针,以使得对象被释放,只有当没有指针指向它了,也是在STL: shared_ptr

数组构造函数

对于堆栈上的一系列项目,如

A array[10];
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)