在类定义中使用内置数组,但大小推迟到派生类会导致隐藏吗?
Posted
技术标签:
【中文标题】在类定义中使用内置数组,但大小推迟到派生类会导致隐藏吗?【英文标题】:Would using a built in arrays within a class definition, but with size deferred to derived class cause hiding? 【发布时间】:2016-04-27 18:48:09 【问题描述】:树中的每个类都依赖于与其他用于监控电压和电流传感器的类(通常命名为 1、2、3...)有关系。问题是这些传感器中有多少取决于正在模拟的单元类型。这意味着只有派生类会知道。
#include <iostream>
class A
public:
A() ;
virtual void Display() = 0;
protected:
int array[]; // size is purposefully left out in base class
;
class B : public A
public:
B(int numbers[4]);
virtual void Display();
protected:
int array[4]; // 4 sensors are required, number fixed at compile time
B::B(int numbers[4])
for(int i=0; i<4; i++)
array[i] = numbers[i];
void B::Display()
cout << " B numbers are: ";
for(int i = 0; i < 4; i++)
cout << array[i] << " ";
cout << endl;
class C : public A
public:
C(int numbers[8]);
virtual void Display();
protected:
int array[8]; // 8 sensors needed, number fixed at compile time
;
C::C(int numbers[8])
for(int i=0; i<8; i++)
array[i] = numbers[i];
void C::Display()
cout << " C numbers are: ";
for(int i = 0; i < 8; i++)
cout << array[i] << " ";
cout << endl;
这个驱动表明在使用 g++ 编译器时这在技术上可以工作,但我担心我可能会通过在 B 和 C 类中重新声明数组来隐藏数据。
main()
int B_numbers[] = 1,2,,3,4;
int C_numbers[] = 5,6,7,8,9,10,11,12;
B b(B_numbers[]);
C c(C_numbers[]);
b.Display();
c.Display();
感谢您提供的任何建议。
【问题讨论】:
您不能覆盖成员数据(您正在创建独立数组)。int array[];
是零大小的数组。是时候研究模板了。
您的第一个问题是 C++ 中不允许使用零长度数组,因此 GCC 扩展认为这不是可移植的。
考虑在基类virtual int* Array()
中添加一个虚函数,派生类实现返回指向其数组的指针。
我一直在研究使用 std:;array 或 std::vector ,到目前为止更喜欢前者,因为大小在编译时是固定的。使用 std::array 是否仍然允许我将数组的大小推迟到派生类?
@Cam2025 你不能推迟类的大小直到一些后续定义,所以不可能推迟成员的大小或虚拟化。
【参考方案1】:
您显示的任何代码中都没有使用A::array
,因此您可以将其删除为不必要的。 B
和 C
只是拥有自己的个人数组,他们各自覆盖的 Display()
知道如何处理 - A
不需要在这里涉及。只要有:
struct A
virtual void Display() = 0;
;
请注意,就构造函数而言,B(int numbers[4]);
实际上与 B(int *numbers)
没有任何不同,那里的数字只是给人一种安全的错觉——我可以轻松地将错误大小的数组传递到那里。出于这个原因,更喜欢使用std::array
- 它具有可复制构造的额外好处:
class B : public A
public:
B (std::array<int, 4> const& arr)
: array(arr)
virtual void Display();
protected:
std::array<int, 4> array;
【讨论】:
【参考方案2】:函数可以设为“虚拟”,这意味着调用的实际函数将通过在对象的 vtable 中查找给定对象来确定。这就是重载的工作原理。为派生类实例化的对象将有一个指向派生函数的 vtable。
C++ 不会对数据成员执行此操作。派生类的数据成员与基成员不同。如果您尝试访问该数组,您选择哪一个将基于指向对象的变量的类型,而不是对象本身的类型。而这不是一件好事。
C 可以很容易地射中自己的脚; C++ 让它变得更难,但是当你这样做时,它会把你的整条腿都吹掉。 —Bjarne Stroustrup 的常见问题解答
【讨论】:
一个明确的问题,因为层次结构在完成后将有 3 个级别,基类,数组大小已知的中间类,然后是具有特定配置调整的“叶”类到各种虚函数。【参考方案3】:有很多方法可以解决这个问题。
当您在基类中将array[]
声明为受保护时,这意味着所有派生类都可以访问它(因此您不必重新定义它)。
如果您想确定您的数据始终符合预期,您可以删除额外的 array
定义,因为它们会产生歧义(您有一个同名的基类和派生类成员),并声明数组的预期大小作为受保护变量,然后您可以在每个派生类的构造函数中分配它。
另一种编码方式是使用向量,如下所示:
#include <iostream>
#include <vector>
using namespace std;
class A
public:
A() ;
virtual void Display() = 0;
protected:
vector<int> array;
int size;
;
class B : public A
public:
B(int *numbers);
virtual void Display();
;
B::B(int *numbers)
size=4;
for(int i=0; i<size; i++)
array.push_back(numbers[i]);
void B::Display()
cout << " B numbers are: ";
for(int i = 0; i < size; i++)
cout << array[i] << " ";
cout << endl;
class C : public A
public:
C(int *numbers);
virtual void Display();
;
C::C(int *numbers)
size=8;
for(int i=0; i<size; i++)
array.push_back(numbers[i]);
void C::Display()
cout << " C numbers are: ";
for(int i = 0; i < size; i++)
cout << array[i] << " ";
cout << endl;
int main()
int B_numbers[] = 1,2,3,4;
int C_numbers[] = 5,6,7,8,9,10,11,12;
B b(B_numbers);
C c(C_numbers);
b.Display();
c.Display();
return 0;
这样,您只需在每个类(构造函数)的一个位置声明大小,并且只有一个可能的容器可以将您的数据保存在对象中。您也不必担心内存管理。
如果您想更进一步,您可以在任何地方使用向量(和迭代器),这将确保您的输入大小始终与您的存储大小相匹配。
【讨论】:
【参考方案4】:您可能会受益于使用模板化方法在基类中提供一个数组,派生类可以使用该数组并在编译时定义其大小。
类似这样的:
#include <array>
#include <iostream>
template<size_t N>
class A
public:
A(): arr
A(const std::array<int, N>& arr): arrarr
virtual ~A() = default; // needs virtual destructor
void Display() const // doesn't need to be virtual
for(auto n: arr) // generic code
std::cout << n << ' ';
std::cout << '\n';
int Get(size_t n) const return arr.at(n);
void Set(size_t n, int value) arr.at(n) = value;
protected:
std::array<int, N> arr;
;
class B: public A<4>
public:
B(const std::array<int, 4>& numbers): A(numbers)
;
class C: public A<8>
public:
C(const std::array<int, 8>& numbers): A(numbers)
;
int main()
std::array<int, 4> B_numbers = 1, 2, 3, 4;
B b(B_numbers);
C c(5, 6, 7, 8, 9, 10, 11, 12);
b.Display();
c.Display();
输出:
1 2 3 4
5 6 7 8 9 10 11 12
这种方法的好处是,通过在基类中编写泛型函数(仅依赖于 std::array
类的属性,例如 arr.size()
和 迭代器),您可以节省创建时间相似的类,只是大小不同。
【讨论】:
以上是关于在类定义中使用内置数组,但大小推迟到派生类会导致隐藏吗?的主要内容,如果未能解决你的问题,请参考以下文章