从内存的角度来说,是不是抽象类会分配内存,而接口不会呢。
不过,接口里那些函数的首地址总得需要内存空间的吧。
请大家帮我解开这个疑惑。
接口是一种契约,契约是不包含实现的。接口(契约)的含义就是,你要实现契约里的一些成员(包括属性/方法),至于你如何实现的我不管,只要有实现就可以。而类就是一种实现方式。抽象类之不过是某个类不能被直接实例化,它本身是可以包含实现的(比如你把一些逻辑实现在里面这样它的子类就不用实现了)。然后你说的分配内存的问题,要搞清楚“声明一个类/定义一个类”和“创建一个类的实例对象”两者的区别。
interface IFlyable
{
void Fly();
}
abstract class Bird : IFlyable
{
public void Fly() { }
}
class Plane : IFlyable
{
public void Fly() { }
}
以上只是声明了一些类/接口,并没有创建任何对象,因此并没有对这些对象实例分配内存*。
Plane p = new Plane();
这样才是创建对象,才会为对象分配内存。你说的“接口里那些函数的首地址总得需要内存空间的吧”是对的,当一个方法被执行的时候,CLR会检查当前方法用到了哪些类型。比如我上面那句,用到了IFlyable和Plane,他们的类型信息会在方法开始前被加载到内存中去。
非常感谢@水牛刀刀的回复。
我明白接口的定义,比如在abstact class A中定义一个"const int i = 1", 在其他类中可以直接用A.i这个常量。
但假设接口也可以这样,在interface IB中也可以定义一个"const int i = 1", 在其他类中可以直接用IB.i这个常量。当然是不可以这样的现在。
为什么抽象类可以呢,是不是因为抽象类在运行时得到了该类的指针,通过偏移找到了i这个常量。而接口在内存中不存在指针,故无法找到i这个常量呢。
如何单从理论上接口的定义规范我明白不应该定义常量,但实现上有什么相悖的地方吗?我还是有些困惑。
@leon032: 如果你是想搞清楚这个的话,那我只能说“理论上接口也可以这么做的,但是感觉上不太对”,没有人说“接口不可以”,我相信如果微软团队想做成“接口可以”完全可以做到。那现在的问题是:有没有必要去做和这么做了对不对。在我看来完全没有必要让接口中也可以定义常量,因为没有哪种情况下是是有用的。如果你能想象到,你可以给我讲讲。
@水牛刀刀: 上午有个同事在做一个维护的项目,需要一些常量。可能是之前的项目也不规范,他为了省事就想在之前的接口中定义一些常量。就是在这个问题上突然想到的一些有关接口中常量的东西。
如果说接口只是提供规范,是一些必须的规则,我觉得readonly的常理也能勉强算上吧。呵呵
总之,非常感谢回复!
1, 只有实体对象才会占用对象。
抽象类和接口都不能被实例化,所以讨论它们占用内存的问题没意义。
2, 要了解对象空间大小,建议你多了解一些“虚函数表(Virtual Table)”知识。
“虚函数表”讲深了很难,尤其是C++多继承,本人也只略知皮毛。但是多了解一点这方面的知识,对OO编程实践会有很大促进。
这方面的资料网上很多,随手一搜一大堆。
感谢@胡屯的回复,我会仔细看看虚函数表的。