【问题标题】:Abstract class init in the initialization list初始化列表中的抽象类init
【发布时间】:2021-11-27 05:56:19
【问题描述】:

我想了解以下 c++ 概念。 class_a 是抽象类,根据抽象类概念,我们不能创建它的任何实例。 我也使用了初始化列表和抽象类,但从未使用过以下概念。 代码中,class_b、class_a的初始化列表被初始化。我想了解在初始化列表中初始化它是什么意思。

 class_b::class_b(int val):nameA::class_a()

在文件A.cpp中

namespace nameA
{
class class_a
{
    public:
        virtual ~class_a(){};
        virtual void process()=0;
};
}

在 fileb.h 文件中

namespace nameB
{
class class_b  : public nameA::class_a
{
    public:
    class_b(int val);
}
}

在 fileb.cpp 文件中

namespace nameB
{
class_b::class_b(int val)
:nameA::class_a() //Want to understand this line...
}

【问题讨论】:

    标签: c++ oop c++11 abstract-class initializer-list


    【解决方案1】:

    通过派生,每个 class_b 对象都将包含一个 class_a 子对象。

    即使您无法实例化 class_a 类型的对象,也可能需要初始化此子对象。考虑一个抽象类也可以有成员。

    如果你有一个接口方面的抽象类(比如在 Java 中),这个抽象类显然不需要初始化。尽管如此,它会在 C++ 中获得一个(空的)默认构造函数,您可以在初始化列表中显式调用它。 (如果不显式调用,会被隐式调用。)

    【讨论】:

    • @Yunnosch:更正了措辞 - 谢谢!
    • "通过派生,每个 class_b 对象都将包含一个 class_a 子对象。"我不太同意这种解释继承的措辞。
    【解决方案2】:

    稍微丰富一点的例子会更清楚。因为如果抽象基类既没有属性也没有方法,就很难看出它是如何初始化的。

    class NamedProcessor {
        std::string name;    // a private attribute
    public:
        NamedProcessor(const std::string &name) : name(name) {}
        virtual ~NamedProcessor() {}
    
        // a pure virtual method to make the class abstract
        virtual void process() = 0;
    
        std::string getName() {
            return name;
        }
    };
    
    class Doubler : public NamedProcessor {
        int value;           // a private attribute
    
    public:
        Doubler(int initial = 1) : NamedProcessor("Doubler") {
            reset(initial);
        }
    
        void reset(int initial) {
            value = initial;
        }
    
        int getValue() {
            return value;
        }
    
        // the concrete implementation
        void process() {
            value *= 2;
        }
    };
    
    int main() {
        // Compiler would croak witherror : variable type 'NamedProcessor' is an abstract class
        // NamedProcessor wrong("Ill formed");
    
        Doubler doubler;
        std::cout << doubler.getName() << "\n";     // name has been initialized...
        return 0;
    }
    

    这里抽象类拥有一个可用于子类的属性。并且这个属性必须在构建时设置,因为它没有公共设置器。该语言必须提供一种方法来初始化抽象子类,这意味着不是构建对象,而是初始化子对象 - 这里设置名称。

    【讨论】:

      【解决方案3】:

      如果类是抽象的,并不意味着它不能有任何构造函数。这意味着你不能用它来创建一个独立的对象。

      所以这里是经典的继承机制:

      • 您创建了一个child_class 对象
      • 它调用child_class()构造函数
      • child_class() 构造函数调用base_class() 构造函数来保证base_class 的字段构建正确
      • 然后为其余的child_class字段执行child_class()构造函数

      在您的示例中,您自己调用 class_a() 构造函数,但无论如何都会调用它。所以总而言之,这不是抽象类,而是简单的继承。

      如果存在class_a字段,你需要有一些初始化机制,这就是为什么你可以调用class_a()构造函数,即使它是抽象类,否则继承机制就没用了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-05-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-13
        • 1970-01-01
        相关资源
        最近更新 更多