简体   繁体   English

将类变量传递给基类构造函数 C++

[英]Passing in a class variable to the base class constructor C++

I have an implementation of a base class which constructs some array of a size that is known at runtime.我有一个基类的实现,它构造了一些在运行时已知的大小数组。 When I call the constructor of the base class, I would like to pass in a reference to one of the values in this array.当我调用基类的构造函数时,我想传入对该数组中某个值的引用。 The following example code illustrates this (my actual code includes error handling that is not relevant here).以下示例代码说明了这一点(我的实际代码包括与此处无关的错误处理)。

#include <iostream>

class Base {
    public:
        int & someInteger;

        Base(int & thisIsSomeInteger) : someInteger(thisIsSomeInteger) {}

};

class Impl : public Base {
    public:
        int * someArray;

        Impl(int size) : 
            someArray(new int[size]),
            Base(someArray[2])
        {}
};

int main()
{
    Impl test(5);

    test.someArray[2] = 20;

    // Not the same!
    std::cout << &test.someInteger << "\n";
    std::cout << &test.someArray[2] << "\n";
}

Desired behaviour期望的行为

Both &test.someInteger and &test.someArray[2] point to the same address in memory. &test.someInteger&test.someArray[2]都指向内存中的相同地址。

Actual behaviour实际行为

&test.someInteger and &test.someArray[2] point to different addresses in memory. &test.someInteger&test.someArray[2]指向内存中的不同地址。 I expect that this is the case because the base class constructor is called first in the initialization list, meaning that someArray hasn't been allocated yet when the base constructor is called.我希望是这种情况,因为在初始化列表中首先调用了基类构造函数,这意味着调用基构造函数时尚未分配someArray

Possible work around可能的解决方法

Initalize someInteger to an address and then change someArray[2] to point to this address instead of whatever address it was allocated to.someInteger为一个地址,然后将someArray[2]更改为指向该地址,而不是分配给它的任何地址。 However, this feels very clunky to me and seems like bad practice.但是,这对我来说感觉很笨拙,而且似乎是不好的做法。

Is there a better way to solve this problem?有没有更好的方法来解决这个问题?

this is the case because the base class constructor is called first in the initialization list这是因为在初始化列表中首先调用了基类构造函数

Yes, it is.是的。 You can use multiple subclasses to control initialization order.您可以使用多个子类来控制初始化顺序。

class Base {
    public:
        int & someInteger;

        Base(int & thisIsSomeInteger) : someInteger(thisIsSomeInteger) {}

};

class ArrayBase {

public:

        int * someArray;
        ArrayBase(int size) : 
            someArray(new int[size]) {}
};

class Impl : public ArrayBase, public Base {
    public:

        Impl(int size) : ArrayBase(size),
            Base(someArray[2])
        {}
};

You could use constructor chaining introducing a private Impl::Impl(int[]) that gets the array as parameter allowing you to determine the reference to pass on to the base class constructor based on the first parameter:您可以使用构造函数链接引入私有Impl::Impl(int[]) ,该私有 Impl::Impl(int[]) 将数组作为参数,允许您根据第一个参数确定要传递给基类构造函数的引用:

class Impl : public Base {
public:
    int* someArray;

    Impl(int size)
        : Impl(new int[size])
    {
    }

private:
    Impl(int arr[])
        : Base(arr[2]),
        someArray(arr)
    {
    }
};

Note: If you implement destructor logic to free the memory, you need to be extra careful to not access Base::someInteger in Base::~Base() , since Impl::~Impl() executes the base class destructor at its very end after everything Impl -related has been freed.注意:如果你实现析构逻辑来释放内存,你需要格外小心,不要在Base::~Base()中访问Base::someInteger ,因为Impl::~Impl()会在其非常执行基类析构函数在所有与Impl相关的内容都被释放后结束。

Also there are potential issues with freeing the array, if Base::Base(int&) can throw and exception;如果Base::Base(int&)可以抛出异常,则释放数组也存在潜在问题; It would be preferrabe to have an object such as std::unique_ptr<int[]> or std::vector<int> owning the array to ensure the memory is freed, if an error happens.如果发生错误,最好让std::unique_ptr<int[]>std::vector<int>等对象拥有该数组,以确保释放内存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM