在另一个对象B中创建对象A时,对象A是否在对象B本地,并且对象A是否会超出对象B的实例化而存在?

时间:2019-07-06 22:58:23

标签: c++ class oop object constructor

我的目标是创建两个类LEDPWM,目的是每个LED对象都创建一个本地PWM对象来控制亮度。这样的想法是,用户可以创建LED对象,而不必设置PWM对象,同时保留为电动机速度控制等单独创建PWM对象的选项。< / p>

当我实例化PWM对象内的LED对象时,就会出现问题。代码编译没有错误;但是,结果是PWM对象的构造函数完成后,LED对象就消失了。 (当我触发相应的任务时,与PWM模块相关的事件均未发生。具体来说,pwm.stoppwm.start函数使用空的while循环来等待特定的事件这些事件会在任务完成时发出信号,并且在循环完成事件发生时,循环快捷方式会自动启动任务。触发适当的任务时,这些事件都不会发生。数据表警告:“请注意,必须启用外设在使用任务和事件之前。”这使我相信pwm.enable()尚未运行。)

ohlemacher谈到constructors inside constructors

  

“ ...它只是不执行您想要的操作。内部构造函数将构造一个临时本地对象,一旦外部构造函数返回,该本地对象将被删除。”

是否有更好的方法在创建PWM对象时自动生成LED对象?是否可以在不使PWM对象成为LED对象的成员的情况下做我想做的事情?

pwm.h

#ifndef rav_nrf52840_pwm_h
#define rav_nrf52840_pwm_h

#include "rav_nrf52840_baseConst.h"

typedef enum {DIV1,DIV2,DIV4,DIV8,DIV16,DIV32,DIV64,DIV128} prescaler;
typedef enum {PWM0,PWM1,PWM2,PWM3} pwmModule;
typedef enum {COMMON,GROUPED,INDIVIDUAL,WAVEFORM} decoderLoad;

class PWM {

private:

    unsigned int base_address;

    void enable_pwm (bool en);

    bool start_pwm (void);

    void stop_pwm (void);

public:

    PWM ();

    PWM (pwmModule module, bool looping, bool mode, int count, prescaler scale);

    void init (decoderLoad load, bool decoder_mode, int loop_count);

    void sequence (int seq_number, unsigned int *pointer, int count, int refresh, int enddelay);

    void pinSelect (int channel, int port, int pin, bool disconnect);

    void enable (void);

    void disable (void);

    bool start (void);

    void stop (void);
};

#endif

pwm.cpp

#include "rav_nrf52840_pwm.h"
#include <cstdint>

PWM::PWM (){
    #ifndef rav_nrf52840_pwm_pwm3
    #define rav_nrf52840_pwm_pwm3
    pwmModule module = PWM3;
    #else
    #ifndef rav_nrf52840_pwm_pwm2
    #define rav_nrf52840_pwm_pwm2
    pwmModule module = PWM2;
    #else
    #ifndef rav_nrf52840_pwm_pwm1
    #define rav_nrf52840_pwm_pwm1
    pwmModule module = PWM1;
    #else
    #ifndef rav_nrf52840_pwm_pwm0
    #define rav_nrf52840_pwm_pwm0
    pwmModule module = PWM0;
    #endif
    #endif
    #endif
    #endif

    bool looping = true;
    bool mode = 0;
    int count = 0x7FFF;
    prescaler scale = DIV4;
    switch (module){

        default:
            ;
        break;

        case PWM0:
            base_address = BASE_ADDRESS_PWM0;
        break;

        case PWM1:
            base_address = BASE_ADDRESS_PWM1;
        break;

        case PWM2:
            base_address = BASE_ADDRESS_PWM2;
        break;

        case PWM3:
            base_address = BASE_ADDRESS_PWM3;
        break;
    }
    unsigned int * pwm_mode_reg = (unsigned int *)(base_address + REGISTER_OFFSET_PWM_MODE);
    unsigned int * countertop_reg = (unsigned int *)(base_address + REGISTER_OFFSET_COUNTERTOP);
    unsigned int * prescaler_reg = (unsigned int *)(base_address + REGISTER_OFFSET_PRESCALER);
    unsigned int * shortcut_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SHORTS);
    *pwm_mode_reg = mode;
    *countertop_reg = count;
    *prescaler_reg = scale;
    if (looping){
        *shortcut_reg = 0x04;  //  Enable looping
    }
}

PWM::PWM (pwmModule module, bool looping, bool mode, int count, prescaler scale){
    switch (module){

        default:
            ;
        break;

        case PWM0:
            base_address = BASE_ADDRESS_PWM0;
        break;

        case PWM1:
            base_address = BASE_ADDRESS_PWM1;
        break;

        case PWM2:
            base_address = BASE_ADDRESS_PWM2;
        break;

        case PWM3:
            base_address = BASE_ADDRESS_PWM3;
        break;
    }
    unsigned int * pwm_mode_reg = (unsigned int *)(base_address + REGISTER_OFFSET_PWM_MODE);
    unsigned int * countertop_reg = (unsigned int *)(base_address + REGISTER_OFFSET_COUNTERTOP);
    unsigned int * prescaler_reg = (unsigned int *)(base_address + REGISTER_OFFSET_PRESCALER);
    unsigned int * shortcut_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SHORTS);
    *pwm_mode_reg = mode;
    *countertop_reg = count;
    *prescaler_reg = scale;
    if (looping){
        *shortcut_reg = 0x04;  //  Enable looping
    }
}





// PRIVATE

void PWM::enable_pwm (bool en){
    unsigned int * pwm_enable_reg = (unsigned int *)(base_address + REGISTER_OFFSET_ENABLE);
    *pwm_enable_reg = en;
}

bool PWM::start_pwm (void){
    unsigned int * start_seq0_task = (unsigned int *)(base_address + TASK_OFFSET_SEQSTART_0);
    volatile unsigned int * seq0_started_event = (unsigned int *)(base_address + EVENT_OFFSET_SEQSTARTED_0);
    *start_seq0_task = true;
    while(!*seq0_started_event){}
    *seq0_started_event = false;
    return 1;
}

void PWM::stop_pwm (void){
    unsigned int * pwm_stop_task = (unsigned int *)(base_address + TASK_OFFSET_PWM_STOP);
    volatile unsigned int * pwm_stopped_event = (unsigned int *)(base_address + EVENT_OFFSET_STOPPED);
    *pwm_stop_task = true;
    while(!*pwm_stopped_event){}
    *pwm_stopped_event = false;
}





// PUBLIC

void PWM::init (decoderLoad load, bool decoder_mode, int loop_count){
    unsigned int * decoder_reg = (unsigned int *)(base_address + REGISTER_OFFSET_DECODER);
    unsigned int * loop_reg = (unsigned int *)(base_address + REGISTER_OFFSET_LOOP);
    *decoder_reg = load;
    if (decoder_mode){
        *decoder_reg |= 0x100;
    }
    *loop_reg = loop_count;
}

void PWM::sequence (int seq_number, unsigned int *pointer, int count, int refresh, int enddelay){
    unsigned int * seq_pointer_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SEQ_0_PTR + (MODIFIER_SEQ * seq_number));
    unsigned int * seq_count_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SEQ_0_CNT + (MODIFIER_SEQ * seq_number));
    unsigned int * seq_refresh_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SEQ_0_REFRESH + (MODIFIER_SEQ * seq_number));
    unsigned int * seq_enddelay_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SEQ_0_ENDDELAY + (MODIFIER_SEQ * seq_number));
    *seq_pointer_reg = reinterpret_cast<std::uintptr_t>(pointer);
    *seq_count_reg = count;
    *seq_refresh_reg = refresh;
    *seq_enddelay_reg = enddelay;
}

void PWM::pinSelect (int channel, int port, int pin, bool disconnect){
    unsigned int * pin_select_reg = (unsigned int *)(base_address + REGISTER_OFFSET_PSEL_OUT_0 + (MODIFIER_PSEL_OUT * channel));
    *pin_select_reg = ((disconnect << 31) | (port << 5) | pin);
}

void PWM::enable (void){
    enable_pwm(true);
}

void PWM::disable (void){
    enable_pwm(false);
}

bool PWM::start (void){
    bool pwm_seq_started = start_pwm();
    return pwm_seq_started;
}

void PWM::stop (void){
    stop_pwm();
}

led.h

#ifndef rav_nrf52840_led_h
#define rav_nrf52840_led_h

#include "rav_nrf52840_macros.h"
#include "rav_nrf52840_pwm.h"

typedef enum {RED = 1,GREEN = 2,YELLOW = 3,BLUE = 4,MAGENTA = 5,CYAN = 6,WHITE = 7} ledState;

class LED {

private:

    PWM pwm;

    bool pwm_sequence_started_flag;

    bool LED_activeLow_flag;

    bool LED_RGB_flag;

    int  LED_portNumber[3];

    int  LED_pinNumber[3];

    int  LED_color;

    int  LED_intensity;

    unsigned int sequence_0[4];

public:

    LED (bool activeLow,int portNumber[3],int pinNumber[3]);  //  Use this format for RGB LEDs. Port and pin numbers must be listed in order: red, green, then blue.

    LED (bool activeLow,int portNumber,int pinNumber);  //  Use this format for single color LEDs

    void on (ledState color, int brightness);  //  Do not use this format with single color LEDs. Valid options for brightness are 0 - 100(%)

    void off (void);
};

#endif

led.cpp

#include "rav_nrf52840_led.h"

LED::LED (bool activeLow,int portNumber[3],int pinNumber[3]) : pwm(){
    LED_RGB_flag = true;
    LED_activeLow_flag = activeLow;
    LED_portNumber[0] = portNumber[0];
    LED_portNumber[1] = portNumber[1];
    LED_portNumber[2] = portNumber[2];
    LED_pinNumber[0] = pinNumber[0];
    LED_pinNumber[1] = pinNumber[1];
    LED_pinNumber[2] = pinNumber[2];
    pwm.init(INDIVIDUAL,0,0xFFFF);
    pwm.sequence(0,sequence_0,4,0,0);
    pwm.pinSelect(0,LED_portNumber[0],LED_pinNumber[0],false);
    pwm.pinSelect(1,LED_portNumber[1],LED_pinNumber[1],false);
    pwm.pinSelect(2,LED_portNumber[2],LED_pinNumber[2],false);
    pwm.enable();
}

LED::LED (bool activeLow,int portNumber,int pinNumber) : pwm(){
    LED_RGB_flag = false;
    LED_activeLow_flag = activeLow;
    LED_portNumber[0] = portNumber;
    LED_pinNumber[0] = pinNumber;
    pwm.init(INDIVIDUAL,0,0xFFFF);
    pwm.sequence(0,sequence_0,4,0,0);
    pwm.pinSelect(0,LED_portNumber[0],LED_pinNumber[0],false);
    pwm.enable();
}





// PRIVATE

int  LED_color = RED;  //  Default value for LED_color is RED.
int  LED_intensity = 0xFFFF;  //  Default value for LED_intensity is 0xFFFF.





// PUBLIC

void LED::on (ledState color, int brightness){
    LED_intensity = brightness;//(scale(brightness,0,100,0x8000,0xFFFF));
    if (pwm_sequence_started_flag){
        pwm.stop();
        pwm_sequence_started_flag = false;
    }
    if (LED_RGB_flag){
        LED_color = color;
        if (brightness >= 0xFFFF){//100){
            LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 0:1) : writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 1:0);
            LED_activeLow_flag ? writePin(LED_portNumber[1],LED_pinNumber[1],readBit(LED_color,1) ? 0:1) : writePin(LED_portNumber[1],LED_pinNumber[1],readBit(LED_color,1) ? 1:0);
            LED_activeLow_flag ? writePin(LED_portNumber[2],LED_pinNumber[2],readBit(LED_color,2) ? 0:1) : writePin(LED_portNumber[2],LED_pinNumber[2],readBit(LED_color,2) ? 1:0);
        }
        else{
            sequence_0[0] = LED_intensity;
            sequence_0[1] = LED_intensity;
            sequence_0[2] = LED_intensity;
            pwm_sequence_started_flag = pwm.start();
        }
    }
    else{
        if (brightness >= 100){
            LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 0:1) : writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 1:0);
        }
    }
}

void LED::off (void){
    if (LED_RGB_flag){
        LED_activeLow_flag ? writePin(LED_portNumber[1],LED_pinNumber[1],1) : writePin(LED_portNumber[1],LED_pinNumber[1],0);
        LED_activeLow_flag ? writePin(LED_portNumber[2],LED_pinNumber[2],1) : writePin(LED_portNumber[2],LED_pinNumber[2],0);
    }
    LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],1) : writePin(LED_portNumber[0],LED_pinNumber[0],0);
}

main.cpp

#include "rav_nrf52840_base.h"
#include "rav_nrf52840_led.h"


int main(void){  //  TX

    setupClock (HF_64MHz_XTAL, START);
    setupClock (LF_32_768kHz_XTAL, START);

    setupPin (0, 3,INPUT);
    pullPin  (0, 3,PULLUP);
    setupPin (0,18,INPUT);  //  External (? Ohm) pullup resistor.
    setupPin (0,22,OUTPUT);
    writePin (0,22,HIGH);
    setupPin (0,23,OUTPUT);
    writePin (0,23,HIGH);
    setupPin (0,24,OUTPUT);
    writePin (0,24,HIGH);

    int my_led_ports[3] = {0,0,0};
    int my_led_pins[3] = {23,22,24};  //  RED, GREEN, BLUE
    LED led(true,my_led_ports,my_led_pins);


    for(;;){
        if (readPin(0,3)){
            ;
        }
        else{
            led.on(RED,0xFFFF);
        }
        if (readPin(0,18)){
            ;
        }
        else{
            led.on(RED,0xF000);
        }
    }
    return -1;
}

为进行比较,下面是可以使用的旧版本代码(没有PWM的{​​{1}}成员)。文件LEDpwm.h与新版本中的文件相同。

led.h -旧(工作)版本

pwm.cpp

led.cpp -旧(工作)版本

#ifndef rav_nrf52840_led_h
#define rav_nrf52840_led_h

#include "rav_nrf52840_macros.h"

typedef enum {RED = 1,GREEN = 2,YELLOW = 3,BLUE = 4,MAGENTA = 5,CYAN = 6,WHITE = 7} ledState;

class LED {

private:

    bool LED_activeLow_flag;

    bool LED_RGB_flag;

    int  LED_portNumber[3];

    int  LED_pinNumber[3];

    int  LED_color;

    int  LED_intensity;

public:

    LED (bool activeLow,int portNumber[3],int pinNumber[3]);  //  Use this format for RGB LEDs. Port and pin numbers must be listed in order: red, green, then blue.

    LED (bool activeLow,int portNumber,int pinNumber);  //  Use this format for single color LEDs

    void on (ledState color, int brightness);  //  Do not use this format with single color LEDs. Valid options for brightness are 0 - 100(%)

    void off (void);
};

#endif

main.cpp -旧(工作)版本

#include "rav_nrf52840_led.h"

LED::LED (bool activeLow,int portNumber[3],int pinNumber[3]){
    LED_RGB_flag = true;
    LED_activeLow_flag = activeLow;
    LED_portNumber[0] = portNumber[0];
    LED_portNumber[1] = portNumber[1];
    LED_portNumber[2] = portNumber[2];
    LED_pinNumber[0] = pinNumber[0];
    LED_pinNumber[1] = pinNumber[1];
    LED_pinNumber[2] = pinNumber[2];
}

LED::LED (bool activeLow,int portNumber,int pinNumber){
    LED_RGB_flag = false;
    LED_activeLow_flag = activeLow;
    LED_portNumber[0] = portNumber;
    LED_pinNumber[0] = pinNumber;
}





// PRIVATE

bool LED_activeLow_flag;
bool LED_RGB_flag;
int  LED_portNumber[3];
int  LED_pinNumber[3];
int  LED_color = RED;  //  Default value is RED.
int  LED_intensity = 0xFFFF;  //  Default value is 0xFFFF.





// PUBLIC

void LED::on (ledState color, int brightness){
    LED_intensity = brightness;//(scale(brightness,0,100,0x8000,0xFFFF));
    if (LED_RGB_flag){
        LED_color = color;
        if (brightness >= 0xFFFF){//100){
            LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 0:1) : writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 1:0);
            LED_activeLow_flag ? writePin(LED_portNumber[1],LED_pinNumber[1],readBit(LED_color,1) ? 0:1) : writePin(LED_portNumber[1],LED_pinNumber[1],readBit(LED_color,1) ? 1:0);
            LED_activeLow_flag ? writePin(LED_portNumber[2],LED_pinNumber[2],readBit(LED_color,2) ? 0:1) : writePin(LED_portNumber[2],LED_pinNumber[2],readBit(LED_color,2) ? 1:0);
        }
    }
    else{
        if (brightness >= 0xFFFF){//100){
            LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 0:1) : writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 1:0);
        }
    }
}

void LED::off (void){
    if (LED_RGB_flag){
        LED_activeLow_flag ? writePin(LED_portNumber[1],LED_pinNumber[1],1) : writePin(LED_portNumber[1],LED_pinNumber[1],0);
        LED_activeLow_flag ? writePin(LED_portNumber[2],LED_pinNumber[2],1) : writePin(LED_portNumber[2],LED_pinNumber[2],0);
    }
    LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],1) : writePin(LED_portNumber[0],LED_pinNumber[0],0);
}

2 个答案:

答案 0 :(得分:1)

新旧代码之间存在逻辑上的区别。罪魁祸首是其中之一。另外,您可以摆脱一些无用的代码。最后,似乎您误解了奥勒玛查赫对另一个问题的回答。


我看到的新旧版本之间最明显的逻辑差异是,新版本默认构造PWM对象,而旧版本使用参数化构造函数。通过使用旧的工作版本并将行PWM pwm(PWM0,true,0,0x7FFF,DIV4);更改为PWM pwm{};,可以查看这是否是导致问题的原因。您可以通过更改两个LED构造函数来为包含的PWM对象指定参数来修复新版本。将: pwm(){更改为: pwm(PWM0,true,0,0x7FFF,DIV4){

另一个逻辑差异是旧版本称为led.off(),而新版本称为led.on(RED,0xF000);。由于off()函数未更新,因此在此处协调逻辑并不像将调用更改为LED::off()那样简单。要检查这种差异,请注释掉旧的LED::off()函数中的所有代码。修复新版本需要更多的精力。由于我怀疑选择PWM构造函数是真正的罪魁祸首,所以我现在将跳过该操作。

其他逻辑上的差异似乎不太可能引起您的症状,但是无论如何我都会列出它们。旧版本不会为频道1和2调用PWM::pinSelect,而新版本会。旧版本将pwm_sequence_started_flag初始化为0(隐式转换为false),而新版本对此标志没有显式初始化。


led.cpp的新旧版本中,都有一个标记为“ // PRIVATE”的部分什么都没有完成。本节定义一些(全局)变量,它们与LED类的成员具有相同的名称。您的LED成员函数不引用这些变量;当LED::on()设置LED_intensity时,它将设置成员this->LED_intensity,而不是全局::LED_intensity。另外,您的其他源文件不太可能引用这些全局变量,因为它们未在led.h中声明。删除这些未使用的声明。

虽然不是严格没用,但您也可以摆脱void的某些用途。在C ++(而不是C)中,可以使用bool start_pwm ();而不是bool start_pwm (void);来声明不带参数的函数。跳过“ void”意味着专门用于阅读代码的Smidgen较少的脑力,因此,对于理解代码的Smidgen则具有较大的脑力。 Smidgens可以加起来。

使用typedef为枚举命名的过程也看起来像是C ++中引入的C-ism。尝试使用enum pwmModule {PWM0,PWM1,PWM2,PWM3};代替typedef enum {PWM0,PWM1,PWM2,PWM3} pwmModule;。再次,更少的代码需要阅读。

关于简化代码的主题,行

LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 0:1) : writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 1:0);

是一个粗读。如果您从对writePin()的调用中分离出最后一个参数的计算,则将更容易看到发生了什么。逻辑上等效(假设参数为int

int foo = readBit(LED_color,0) ? (LED_activeLow_flag ? 0 : 1) : (LED_activeLow_flag ? 1 : 0);
writePin(LED_portNumber[0], LED_pinNumber[0], foo);

这清楚表明,无论条件如何,都将调用writePin(),并且前两个参数也与条件无关。这只是可以改变的最终参数。


我们继续前进到ohlemacher's answer。声称“它只是做不到您想要的事情”是指在构造函数主体内为类调用构造函数。也就是说,给定class A,编写类似A::A(bool) { A(); }的内容。在构造函数主体内创建一个对象,该对象自然会在构造函数返回时被销毁。

此外,ohlemacher回答的问题是关于为构造函数调用与构造函数相同的类(也称为C ++ 11中引入的“委托构造函数”)。您所关心的情况是调用数据成员的构造函数。对于数据成员来说,自从该语言标准化以来,member initializer lists就可以使用了。

答案 1 :(得分:0)

最简单的方法是使用智能指针。使LED对象包含一个std::shared_ptr<PWM>对象,可以在构造函数或成员函数中随时使用std :: make_shared创建该对象。这样,LED死亡时,您既可以自动清除对象,又可以将PWM对象复制到其他位置,以便在LED被破坏时持久存在。

这样,您可以使任何类按需包含另一个类,并且仍然能够轻松清除。