我正在开发一个基于Arduino的系统(即嵌入式系统)的项目,并且代码的ROM数量有限。
我发现自己需要几种不同类型的集合类(例如List
,Stack
,Queue
)。
写完这些之后,我注意到除了使它们表现不同的特征(例如Add
vs Push
vs Enqueue
,Pop
vs Dequeue
)之外,它们共享一个许多常见功能(例如,它们具有完全相同的字段)。
这让我想到,如果我要创建一个包含其他类的所有常用功能的基类(让我们称之为Collection
)并使其他类继承它,并让它们只实现不同的功能,这会导致编译代码更少吗?
我期待它会因为子课程都可以参考父母对常用功能的实现,但我可能是错的,所以在尝试这个改变之前我宁愿问一下。
好的,为了进一步澄清这一点,因为人们似乎误解了,请考虑这些假设的课程:
class A
{
protected:
int value;
public:
void assign(int other)
{
this->value = other;
}
}
class B : public A
{
public:
void assignAdd5(int other)
{
this->value = other + 5;
}
}
然后是代码:
A a = A();
B b = B();
a.assign(4);
b.assign(4);
我期望assign
在两种情况下都引用相同的方法(因此编译的代码块相同),尽管类型不同,因为B
是A
的子类。如果是这种情况,那么具有类似功能的类都将从实现相似性的单个基类继承,这将产生比使每个类单独实现功能更少的编译代码,因为每个子类将使用相同的函数。
我提供的有关提示此问题的情况的信息仅仅是背景,我知道是否是任何编译器的情况,而不仅仅是我使用的那个(和我完全明白,答案可能是“有些编译器可能会这样做,但并非所有编译器都这样做,而且这是一个完全可以接受的答案。”
答案 0 :(得分:1)
我无法给出明确答案,但我想分享我的发现。实际上我并不像我预期的那样容易衡量差异。不要把代码太严肃,我只是尝试随机的东西,看它是否有任何影响...
#include <iostream>
#define DERIVED
#define BASE_STUFF int a,b,c,d,e,f,g,h,i,k,m,n,o,p,q,r,s,t,u,v,w,x,y,z; \
double foo1(int x){return x;} \
double foo2(int x){return x;} \
double foo3(int x){return x;} \
double foo4(int x){return x;} \
Base* foo5(Base* x){return x;} \
FPTR foo5(FPTR a,FPTR b,FPTR c){return a;}
typedef double (*FPTR)(int,int,double);
struct Base { BASE_STUFF };
#ifdef DERIVED
struct Derived : Base{double a0,a1,a2,a3,a4,a5,a6,a7;};
#endif
#ifndef DERIVED
struct Derived {
double a0,a1,a2,a3,a4,a5,a6,a7;
BASE_STUFF
};
#endif
int main(int argc, char *argv[])
{
Base b;
b.x = 1;
std::cout << b.foo1(b.x);
std::cout << b.foo5(&b)->foo2(b.a);
Derived n;
n.a0 = 2;
std::cout << n.foo1(n.a0);
}
我必须再次检查数字,但令我惊讶的是,与c风格iostream
相比,使用prinft
时可执行文件更小。
当我用(g ++ 4.9.2)
编译时g++ main.cpp -Os -fno-exceptions -s
我得到了13.312 kB的可执行文件。这与被定义的DERIVED
无关。但是,当我用
g++ main.cpp -Os -fno-exceptions
大小为43.549 kB。再次独立于DERIVED
被定义与否。
我的结论是
答案 1 :(得分:0)
写一个完整的容器。
私下继承它。使用using
将要公开的方法带入视图。
编译器最多会为dtor / ctor创建一些极短的方法。