【问题标题】:C++: How to enforce derived class to set base member variables?C++:如何强制派生类设置基成员变量?
【发布时间】:2013-10-08 23:12:29
【问题描述】:

我有一个带有成员变量的基类(最好是private),我需要强制派生类使用基于其实现的值对其进行初始化;很像纯虚函数。

为了澄清,我想在 Base 中声明一个成员,让派生类对其进行初始化,如果不这样做,则会出现编译器错误。在下面的代码中,我将Base 的默认构造函数声明为protected。然后将Derived的默认构造函数声明为private

class Base {
private:
    int _size;

protected:
    Base(){}
    /* pure virtual methods */

public:
    Base(int size) : _size(size){} // must enforce derived to call this.
    virtual ~Base(){}

    /* more pure virtual methods */
};

class Derived : public Base {
private:
    Derived() {}
public:
    Derived(int size) : Base(size) {
        //Base::Base(size);
    }
};

int main()
{
    Derived* d1 = new Derived();    // throws an error as needed: 
                                    // "Cannot access private member declared in class 'Derived'"

    Derived* d2 = new Derived;      // throws an error as needed: 
                                    // "Cannot access private member declared in class 'Derived'"

    Derived* d3 = new Derived(5);   // works as needed

    return 0;
}

上面代码的问题是,如果Derived的另一个定义没有隐藏默认构造函数。我仍然遇到未初始化的Base::_size

我不知道除了继承之外是否还有其他方法可以解决这个问题,因为我仍然需要派生类来为Base 中声明的几个方法实现它们自己的行为。

任何指针表示赞赏。

【问题讨论】:

  • Base::Base(size); 这可能不是你认为的那样。如果要调用基类ctor,请使用mem-initializer-list:Derived(int size) : Base(size) { /*...*/ }
  • 好的,谢谢。刚刚编辑了代码。
  • 拥有带参数的构造函数会自动移除默认构造函数。你不需要做一个私人的。
  • @NeilKirk 是的,但它不强制用户使用参数化 ctor。如果类没有显式定义默认构造函数,则编译器会自动创建它。对吗?
  • @mbadawi23 如果存在用户声明的 ctor,则将隐式声明默认 ctor。

标签: c++ inheritance


【解决方案1】:

在混淆了调用基类ctor和默认ctor之后,也许解决方案就是在Base中没有默认ctor?

class Base {
private:
    int _size;

public:
    // no default ctor
    Base(int size) : _size(size) {} // must enforce derived to call this.
    virtual ~Base(){}

    /* more pure virtual methods */
};

class Derived : public Base {
public:
    // no default ctor
    Derived(int size) : Base(size){
    }
    // examplary default ctor:
    //Derived() : Base(42) {}
};

int main()
{
    Derived d1;                   // error: no default ctor
    Derived* d2 = new Derived;    // same, but why use the free store?

    Derived d3(5);                // works as needed
    Derived* d4 = new Derived(5); // same, but why use the free store?

    return 0;
}

要明确表示没有默认 ctor,可以使用

class Base {
    /* ... */
    Base() = delete;
    /* ... */
};

【讨论】:

    【解决方案2】:

    使用构造函数

    类 Base1 { 受保护: Base1(int forward) { thingYouWantToHide = 转发; } 私人的: int thingYouWantToHide; };

    class Derived1: public Base1 {
    public:
        Derived1(): Base1(5) {}
    };
    
    class Base2 {
    private:
        int value;
    protected:
        Base2() {
            value = calledToGet();
        }
        virtual int calledToGet() = 0;
    
        virtual ~Base2() {} //shut compiler warnings up
    };
    
    class Derived2: public Base2 {
        virtual int calledToGet() {
            return 5;
        }
    };
    
    int main(int,char**) {
        Derived1 a;
        Derived2 b;
        return 0;
    }
    

    您可能认为 Derived2 会起作用,但请记住,Derived2 直到 Base2 才被构造,所以当 Base2 被构造时 virtual 是一个未定义的引用。

    你应该使用第一种情况,类型特征如果它是一个常量(静态常量)或类型的基础。

    【讨论】:

    • 我不确定我是否理解正确,使用您的Base2Derived2 我收到未解决的Base2::calledToGet() 的链接器错误。自然是因为编译器希望Base2 完整。您能否详细说明您提出的解决方案。
    猜你喜欢
    • 2019-11-13
    • 2015-02-04
    • 2021-09-24
    • 2019-08-22
    • 1970-01-01
    • 2014-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多