c++ - 为什么我们不能在 C++ 中为抽象类创建对象?

标签 c++ object abstract-class

我知道这在 C++ 中是不允许的,但为什么呢?如果允许,会出现什么问题?

最佳答案

根据您的 other question 判断,看来你不明白类是如何运作的。类是对数据进行操作的函数的集合。

函数本身不包含类中的内存。下面的类:

struct dumb_class
{
    void foo(){}
    void bar(){}
    void baz(){}
    // .. for all eternity

    int i;
};

大小为int。无论你有多少函数,这个类只会占用操作 int 所需的空间。当你调用这个类中的函数时,编译器会传递给你一个指针,指向类中数据存放的地方;这是 this 指针。

因此,该函数位于内存中的某处,在程序开始时加载一次,并等待调用数据进行操作。

虚函数不同。 C++ 标准强制要求虚函数的行为应该如何进行,而只是规定该行为应该是什么。通常,实现使用所谓的虚拟表,或简称 vtable。 vtable 是一个函数指针表,它像普通函数一样,只分配一次。

学习这个类,假设我们的实现者使用 vtables:

struct base { virtual void foo(void); };
struct derived { virtual void foo(void); };

编译器需要创建两个 vtable,一个用于 base,一个用于 derived。它们看起来像这样:

typedef /* some generic function pointer type */ func_ptr;

func_ptr __baseTable[] = {&base::foo}; 
func_ptr __derivedTable[] = {&derived::foo}; 

它是如何使用这张表的?当您创建上述类的实例时,编译器会插入一个隐藏指针,该指针将指向正确的 vtable。所以当你说:

derived d;
base* b = &d;
b->foo();

在执行最后一行时,它转到正确的表(在本例中为 __derivedTable),转到正确的索引(在本例中为 0),并调用该函数。如您所见,这将最终调用 derived::foo,这正是应该发生的事情。

请注意,稍后,这与执行 derived::foo(b) 相同,将 b 作为 this 指针传递。

因此,当存在虚方法时,类的大小将增加一个指针(指向 vtable 的指针)。多重继承稍微改变了这一点,但基本上是一样的。您可以在 C++-FAQ 获取更多详细信息。 .

现在,回答你的问题。我有:

struct base { virtual void foo(void) = 0; }; // notice the = 0
struct derived { virtual void foo(void); };

base::foo 没有实现。这使得 base::foo 成为一个纯抽象函数。所以,如果我像上面那样调用它:

derived d;
base* b = &d;
base::foo(b);

我们应该期待什么样的行为?作为纯虚方法,base::foo 甚至不存在。上面的代码是未定义的行为,可以做任何事情,从什么都不做到崩溃,以及介于两者之间的任何事情。 (或者更糟。)

想想一个纯抽象函数代表什么。请记住,函数不接受数据,它们只描述如何操作数据。一个纯抽象函数说:“我想调用这个方法并让我的数据被操纵。你如何做到这取决于你。”

因此,当您说“好吧,让我们调用一个抽象方法”时,您就是在回答上面的问题:“由我决定?不,你来做。”它将回复“@#^@#^”。告诉那些说“这样做”、“不”的人根本没有意义。

直接回答您的问题:

"why we cannot create an object for an abstract class?"

希望你现在明白了,抽象类只定义了具体类应该能够完成的功能。抽象类本身只是一个蓝图;你不是住在蓝图里,你住在实现蓝图的房子里。

关于c++ - 为什么我们不能在 C++ 中为抽象类创建对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2091426/

相关文章:

c++ - 为什么我不能在 VS2008 的类中使用静态成员,例如静态结构?

c++ - 如何调用一个函数并让它运行并返回一个字符?

java - 构建一个对象

c++ - ifstream 读取失败

java - 如何使用 JUnit 测试 Java 中的抽象类?

c++ - 解决链接器错误 : undefined reference to static class members

c++ - 为什么我的代码不输出(仅)数字?

java - 旧的对象引用会发生什么?

java - 来自抽象父类(super class)的抽象方法作为子类中的静态方法

c# - 在 Inherited Class Constructor C# 中强制部分基初始化(和方法)(就像抽象对方法所做的那样)——解决这个问题