我试图理解C ++中的继承。
我想在派生类中动态创建一个数组,并将数组指针传递给基类,然后基类填充数组。最后,我想从派生类中打印数组。
我编写了以下代码,但是当我运行此代码时,程序崩溃并且出现分段错误错误。
我该如何实现?!
class Base {
private:
int* array;
public:
Base(int* a) {
array = a;
for(int i = 0 ; i < 10 ; i++) {
array[i] = i;
}
}
};
class Child : public Base {
private:
int* array;
public:
Child() : array(new int[10]), Base(array) {}
void print() {
for(int i = 0 ; i < 10 ; i++) {
cout << array[i] << endl;
}
}
};
答案 0 :(得分:5)
这里的问题是初始化列表中的项目顺序不会影响实际执行初始化的顺序;只考虑声明成员的顺序。而且,基数的初始化总是先发生。
因此,Child
构造函数实际执行如下:
Base(array)
(此处未设置array
!)array
被分配了有效值。幸运的是,解决此问题所需要做的就是从array
中移除Child
:无论如何它都是多余的:
class Child : public Base {
public:
Child() : Base(new int[10]) {
}
void print() {
for(int i = 0 ; i < 10 ; i++) {
// Make a[] protected in the parent
cout << a[i] << endl;
}
}
};
class Base
{
protected:
int *array;
...
}
如果您不想在父级中保护a
,则可以按照以下方式修改代码(demo):
Child() : Base(array = new int[10]) {}
这不是最理想的,因为冗余成员会保留在Child
的所有实例中。
答案 1 :(得分:3)
即使您以其他顺序编写初始化程序,也会在类成员之前初始化基础子对象。所以这里:
Child(): array(new int[10]), Base(array)
首先使用未初始化的Base
值初始化array
对象。
解决方案包括:
Base::array
访问Child
,因此它不需要自己的副本; print
移至基类中,以便Child
无需访问array
; Child() : Base(array = new int[10])
这样令人讨厌的事情。确保您已启用编译器警告;他们应该抓住这个错误。
答案 2 :(得分:0)
这是因为首先构造了基础对象,然后才构造子对象。
这意味着您的阵列是未初始化的。
在每个招聘人员的开头和结尾放置一些跟踪消息,您将更好地了解事情的运作方式。
答案 3 :(得分:0)
一种解决方案是使用std::array
代替原始指针,如下例所示:
#include <iostream>
#include <array>
template<typename T, std::size_t N>
class Base
{
private:
std::array<T, N> const &array;
public:
Base(std::array<T, N> const &a) : array(a) { }
void print() const {
std::cout << "Printing array from Base class!" << std::endl;
for(auto i : array) std::cout << i << " ";
std::cout << std::endl;
}
};
template<typename T, std::size_t N>
class Child : public Base<T, N> {
private :
std::array<T, N> array;
public:
Child() : Base<T, N>(array) {
for(auto &i : array) i = 10;
}
void print() {
std::cout << "Printing array from Child class!" << std::endl;
for(auto i : array) std::cout << i << " ";
std::cout << std::endl;
}
};
auto main() -> int {
Child<int, 10> c;
c.print();
Base<int, 10> *b = &c;
b->print();
return 0;
}
因此:
您不必担心释放以前分配的内存。
您的Base
类保持对Child类的数组对象的常量引用。因此,您节省了内存。