【问题标题】:Calling the Constructor for the Abstract Base class in C++在 C++ 中调用抽象基类的构造函数
【发布时间】:2017-08-16 13:44:50
【问题描述】:

我知道如果我有一个抽象类,那么我不能创建一个抽象类类型的对象。但是假设“Base”是一个基类,“Derived”是一个派生类。 在基类中,我有一个成员变量名称。

Base.h
Base(string name = "");

Base.cpp
Base(string theName){name = theName);

这不是在创建一个对象吗?

在派生类中,我有成员变量年龄。 现在在派生类默认构造函数中

Derived.h
Derived(string name = "", int theAge = 0);

Derived.cpp
Derived(string theName, int theAge):Base(theName) { age = theAge }

那不是也调用了 Base 的默认构造函数吗? 那么,我可以调用参数化构造函数但不能调用默认构造函数吗?

还有一件事,如果我在基类中有另一个函数而不是纯函数,如果不允许我为基类创建对象,我该如何调用该函数?

提前致谢!

【问题讨论】:

  • 那么 Base 是一个抽象基类还是只是一个基类?我认为可编译的 minimal reproducible example 会有所帮助。
  • Base 构造函数不是创建 对象,它可以初始化 Base 类的实例(对象)。如果你要创建一个Base 对象,你只需定义一个类的变量。
  • 请告诉我们是什么代码导致了您的问题以及错误消息是什么。
  • 另见定义与声明。然后你可以更深入地使用抽象类与具体类。

标签: c++ class c++11 inheritance constructor


【解决方案1】:

我知道如果我有一个抽象类,那么我不能创建一个抽象类类型的对象。

有一个例外:抽象类的对象可以创建为派生类对象的子对象。

事实上,它必须在这种情况下创建,因为这正是 C++ 中继承的工作方式。派生类的对象包含基类的对象(或者通常是基类的对象,因为我们不要忘记 C++ 也支持多重继承)。

标准在 §10.4/1 中非常清楚地说明了这一点:

抽象类是只能用作其他类的基类的类;不能创建抽象类的任何对象除了作为从它派生的类的子对象

你有它:抽象类的实例可能存在于这个限制内。因此,

Base(string theName){name = theName);

这不是在创建一个对象吗?

它和其他构造函数一样;它用于创建对象。鉴于上述规则,类是抽象的这一事实并不重要。

Derived(string theName, int theAge):Base(theName) { age = theAge }

那不是也调用了 Base 的默认构造函数吗?

是的。

那么,我可以调用参数化构造函数但不能调用默认构造函数吗?

所有参数都是默认的构造函数默认构造函数。

还有一件事,如果我在基类中有另一个函数而不是纯函数,如果不允许我为基类创建对象,我该如何调用该函数?

如果它是public 函数,那么任何拥有派生类对象的人都可以调用它(这包括派生类本身)。此外,任何通过指针或对基类的引用访问派生类对象的人都可以调用它。当然,基类本身也可以调用它。

如果它是protected 函数,那么派生类和潜在的进一步派生类可以调用它。

如果是private,那么基类本身就可以调用它。

正如我们在上面所建立的,从技术上讲,您确实为基类创建了一个对象,作为派生类对象内部的子对象。所以原则上,这种情况并不是因为基类是抽象的而特别。


这里要记住的是,定义了语言的技术细节,以便所有基本的面向对象功能都能按预期工作。在日常编程业务中,您不必担心这些事情。

【讨论】:

  • 非常感谢@Christian Hackl 但是当我创建一个指针来调用抽象基类中的公共函数时,它说指针未被识别 Base *p; p->函数();它不起作用。如果我使用关键字 new 像:p=new Base; p->函数();那我怎么称呼它呢?
  • @iNoah: Base *p; 只是创建了一个未初始化的指针。尝试调用 p->function() 是未定义的行为。 p=new Base; 无法编译,因为您尝试创建不是派生类对象的子对象的 Base 对象。您需要创建一个Derived 对象,该对象将自动包含Base。示例:Derived d; Base& b = d; b.function();
  • 这很好,但是如果函数在基类中输出 Hello 而在派生类中输出 Hi,那么即使我按照你提到的那样做,我也会继续将 Hi 作为输出而不是基类的实现.谢谢你的帮助!!我真的很感激
  • @iNoah:你说的是virtual函数吗?在那种情况下,这就是虚函数的全部目的。派生类覆盖基类实现。或者在抽象类的情况下,提供一个基类没有的实现(在所谓的“纯虚”函数的情况下,= 0 语法)。
【解决方案2】:

您将两个不同的概念混为一谈:

  1. 构造一个对象。

  2. 实例化一个对象。

抽象类的构造与任何其他类一样。它可以有自己的自定义构造函数。或者它可以有一个默认构造函数,除非某些条件不允许默认构造函数。

抽象类不能被实例化。正如您自己编写的那样,您“无法创建”抽象类。只能创建派生类(除非派生类也是抽象类)。

当然,创建派生类会创建并构造它的所有基类。包括它的基础抽象类。您的基类的构造函数,抽象类的构造函数,将很乐意履行其义务并构造基抽象类。之后,派生类将构造派生类,然后将整个对象构造并实例化。

【讨论】:

  • 非常感谢。你说的对。但是当我通过编写“Base(theName);”来调用派生类中的 Base 抽象类时在派生类构造函数之后。我不是在初始化基类构造函数吗?那么为什么在 Derived 类中允许这样做,而在 Base 类中却不允许呢?
  • “无法实例化抽象类。” - 这在技术上是不正确的。 C++ 标准明确指出抽象类的实例可能存在——作为派生类的子对象。
【解决方案3】:

这不是在创建一个对象吗??

没有。它只是定义了您将如何构造对象。

那不是也调用了 Base 的默认构造函数吗?那么,我可以调用参数化构造函数但不能调用默认构造函数吗?

是的,它正在调用构造函数,但就像我上面所说的,Base(string theName){name = theName);,没有调用任何东西。它只是一个构造函数定义。

还有一件事,如果我在基类中有另一个函数而不是纯函数,如果不允许我为基类创建对象,我该如何调用该函数?

您可以使用指向/引用派生类实例的基类的指针/引用来调用它。

【讨论】:

    【解决方案4】:

    是的,如果你这样声明构造函数,则不会生成默认构造函数,因为编译器将无法区分你要调用哪个构造函数。例如,这段代码不会被编译,因为 CL1(std::string) 是私有的,并且默认的 CL1() 不存在。

    #include <iostream>
    #include<string>
    using namespace std;
    class CL1{
        CL1(std::string s=""){
            std::cout<<" hello";
        }   
    };
    int main() {
        CL1 instance;
        return 0;
    }
    

    【讨论】:

    • 所有参数都默认的构造函数默认构造函数。因此,您的 CL1 类有一个默认构造函数。
    猜你喜欢
    • 2015-08-29
    • 2014-08-09
    • 2017-04-01
    • 2023-03-04
    • 2011-08-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-26
    • 1970-01-01
    相关资源
    最近更新 更多