复制构造动态分配对象的问题

Problems copy constructing a dynamically allocated object

本文关键字:问题 对象 动态分配 复制      更新时间:2023-10-16

我正在学习C++简介,遇到了一个涉及复制构造函数使用的问题。练习的想法是构造一个电话对象,它本身构造了一个外壳、一根电缆、一个拨号器和一个耳机。这一切都很好,很有指导意义,因为每个类在被调用时都会给出一个cout,但当我尝试以下操作时会出现问题。

Dialer构造了一个由12个按钮组成的数组。Buttons类如下所示:

class Button {
public:
  Button() { std::cout << "Button Constructor " << this << std::endl ; }
  Button(const Button&) { std::cout << "Button Copy Constructor " << this << std::endl ; }
  ~Button() { std::cout << "Button Destructor " << this << std::endl ; }
private:
} ;

我对Dialer类的第一次尝试使用了按钮的静态分配,效果很好。代码:

class Dialer {
public:
  Dialer() {        std::cout << "Dialer Constructor " << this << std::endl ; }
  Dialer(const Dialer &dialer) : buttons(dialer.buttons) {      std::cout << "Dialer Copy Constructor " << this << std::endl ; }
  ~Dialer() { std::cout << "Dialer Destructor " << this << std::endl ; }
private:
  Button buttons[12] ;
} ;

练习的下一步是动态分配按钮,这就是乐趣的开始。以下代码有效:

class Dialer {
public:
  Dialer() : buttons(new Button[12]) { std::cout << "Dialer Constructor " << this << std::endl ; }
  Dialer(const Dialer &dialer) {
        buttons = new Button[12];
        std::cout << "Dialer Copy Constructor " << this << std::endl ;
    }
  ~Dialer() {
            delete[] buttons;
            std::cout << "Dialer Destructor " << this << std::endl ;
    }
private:
  Button* buttons ;
} ;

但这当然不会调用Button复制构造函数。我尝试过很多东西:

buttons = new Button(dialer.buttons)[12];
buttons = new Button(dialer.*buttons)[12];
*buttons = dialer.*buttons;

但我就是做不出来。所有这些尝试都会导致一个错误,即Button类中没有定义匹配的函数。

如果有任何帮助,我将不胜感激:)

干杯,GeneralDuke

以下代码格式调用复制构造函数。

Button a;
Button b=a; //calls the copy constructor of Button class
Button c;
c = a; // calls the overload assignment operator, but not the copy constructor.!

在您的情况下,对于实例阵列,

buttons = new Button[12];
for (int i=0;i<12;i++)
{
     buttons[i] = dialer.buttons[i];
} 

使用operator new[]将使用它们的无参数构造函数来构造那些Button。使用=的进一步赋值将调用赋值运算符。

如果你真的需要调用复制构造函数,你有三个选项:

首先,只需使用std::vector<Button>而不是Button[12]。这将为您处理分配和解除分配,并具有您所需的复制语义:

class Dialer {
public:
    Dialer() : buttons(12) { std::cout << "Dialer Constructor " << this << std::endl ; }
    Dialer(const Dialer &dialer) : buttons(dialer.buttons) {
        std::cout << "Dialer Copy Constructor " << this << std::endl ;
    }
    ~Dialer() { std::cout << "Dialer Destructor " << this << std::endl ; }
private:
    std::vector<Button> buttons;
} ;

第二种选择是根据复制构造函数定义赋值运算符,通常称为复制和交换习惯用法:

Button& operator= (Button other) { /*do swapping*/ }

您的第三种选择是使用std::allocator来分配内存,并在单独的步骤中构造它,允许您调用复制构造函数来构造对象(注意,在实践中永远不要这样做;std::allocator通常用于实现通用容器等,我只是在您的约束范围内展示一个解决方案):

class Dialer {
public:
    Dialer() : buttons() {
        std::allocator<Button> b_alloc;
        buttons = b_alloc.allocate(12);
        for (int i=0; i<12; i++)
        {
            b_alloc.construct(buttons+i); //this line requires C++11
        }
        std::cout << "Dialer Constructor " << this << std::endl ; }
    Dialer(const Dialer &dialer) {
        std::allocator<Button> b_alloc;
        buttons = b_alloc.allocate(12);
        for (int i=0; i<12; i++)
        {
            b_alloc.construct(buttons+i, dialer.buttons[i]);
        }
        std::cout << "Dialer Copy Constructor " << this << std::endl ;
    }
    ~Dialer() {
        std::allocator<Button> b_alloc;
        for (int i=0; i<12; i++)
        {
            b_alloc.destroy(buttons+i);
        }
        b_alloc.deallocate(buttons, 12);
        std::cout << "Dialer Destructor " << this << std::endl ;
    }
private:
    Button* buttons;
} ;

以下代码片段调用复制构造函数:

 Button b;
 Button a=b; // copy constructor called

或者对于您的阵列:

EDIT已更改为按值传递。

void addToArray(Button* arr, Button aButton, int idx)
{
    arr[idx]=aButton;
}
buttons = new Button[12];
for (int i=0;i<12;i++)
{
     addToButtons(buttons,dialer.buttons[i],i);
}

请注意,您在Button类上定义了复制构造函数,而不是在ArrayOfButtons类上。

EDIT:添加的依赖注入样本

我不认为你需要在你的Dialer+Putton关系上使用复制构造函数,更像你的Dialler+Phone关系。

这里有一个使用复制构造函数的示例(但它也需要一个修改过的构造函数):

    class Dialer
    {
       public:
         ...
         Dialer(Button& but):b(but){};
         ....
       private:
         Button b;
    }

代码段:

    {
         Button b1;
         Dialer d(b1);
    }

对于12个按钮,您将在初始化时使用12个参数。也许您应该坚持动态分配,而不是为数组传递值,并为其他类使用复制构造函数?