使用 C/C++ 中的派生类成员变量将参数传递给 Base 构造函数

Posted

技术标签:

【中文标题】使用 C/C++ 中的派生类成员变量将参数传递给 Base 构造函数【英文标题】:Passing arguments to Base constructor using Derived class member variables in C/C++ 【发布时间】:2020-03-24 22:03:50 【问题描述】:

我正在构建一个类来控制一些具有几个不同版本的硬件。由于版本的多样性,某些参数需要硬编码,并且每个版本都不同。但是,除了那些硬编码的参数之外,所有版本都提供相同的功能。

我认为我构建它的方式是使用包含所有所需方法的基类和派生类(DerivedV1、DerivedV2 等),我只需将这些硬编码参数定义为成员变量,然后将它们传递为构造参数到基类。

这是代码的最小示例: (这部署在微控制器上,因此使用数组而不是向量,也忽略了 std::cout 的使用,它只是为了说明问题而包含在这里)

#include <iostream>
using namespace std;

void print_array(uint16_t *array, uint16_t size)
    cout<<"[ ";
    for(int i=0; i < size-1; i++)
      cout<<array[i]<<", ";
    
    cout<<array[size-1]<<" ]"<<endl;



class BaseClass
protected:
  std::string id_;
  uint16_t num_cats_;    
  uint16_t num_dogs_;     
  uint16_t *cat_mapping_;
  uint16_t *dog_mapping_; 
  uint16_t combinations_;

public:  
    BaseClass(string id, uint16_t num_cats, uint16_t num_dogs,
            uint16_t *cat_map, uint16_t *dog_map)

        cout<<"Base Constructor"<<endl;
        id_ = id;
        num_cats_ = num_cats;
        num_dogs_ = num_dogs;
        cat_mapping_ = cat_map;
        dog_mapping_ = dog_map;
        combinations_ = num_cats_*num_dogs_;
        cout<<"Num cats: "<<num_cats_<<endl;
        cout<<"Num dogs: "<<num_cats_<<endl;
        print_array(cat_mapping_, num_cats_);
        print_array(dog_mapping_, num_dogs_);
        cout<<"Combinations: "<<combinations_<<endl;
    

    virtual ~BaseClass();

;


class DerivedClassV1 : public BaseClass 

private:
  uint16_t num_cats_ = 10;
  uint16_t cat_map_[10] = 31, 15, 20, 32, 13, 25, 19, 16, 28, 23;
  uint16_t num_dogs_ = 8;
  uint16_t dog_map_[8] = 5, 25, 23, 4, 13, 15, 14, 26;

public:
  DerivedClassV1(string id) : BaseClass(id, num_cats_, num_dogs_, cat_map_, dog_map_)
    cout<<"Derived Constructor";
  
;


int main()

    DerivedClassV1 dummy("v1");
    return 0;

执行此代码会导致垃圾输出:

基础构造函数 猫数:64 狗数:64 [ 0, 0, 2, 0, 0, 0, 4781, 64, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 4704, 64, 0, 0, 3040, 64, 0, 0, 42640, 13254, 32766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44869, 10268, 32576, 0, 0, 0, 0, 0, 42648, 13254, 32766, 0, 0, 0, 1、0、3456、64、0、0、0、0、0、0、13708、48499] [ 0, 0, 0, 0, 0, 0, 0, 4704, 64, 0, 0, 3040, 64, 0, 0, 42640, 13254, 32766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44869, 10268, 32576, 0, 0, 0, 0, 0, 42648, 13254, 32766, 0, 0, 0, 1, 0, 3456, 64, 0, 0, 0, 0, 0, 0, 13708、48499、5513、17381、3040、64、0、0、42640、13254、32766、0、0、 0, 0, 0, 0, 0, 0, 0, 13708, 63219, 29188, 48153, 13708, 57481, 17840, 484 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4704, 64, 0, 0, 42648, 13254, 32766, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3040, 64, 0, 0, 42640、13254、32766、0、0、0、0、0、3081] 组合:7936 派生构造函数

我在这里做错了什么?为什么发送到 BaseClass 的参数不是派生类中定义的正确参数?

我应该采取不同的做法吗?任何帮助表示赞赏

【问题讨论】:

由于派生类的指针成员在派生类构造函数完成之前不会被初始化,如果基类构造函数保存它们的值,将它们传递给基类构造函数将导致未定义的行为。相反,直接使用初始化列表传递所需的整数值等。不要将值作为派生类的成员 【参考方案1】:

你的程序的行为是未定义的。

从概念上讲,DerivedClassV1::cat_map_ &c。在构造基类时不存在。

指向此类数组的指针(例如基类构造函数中的cat_map)实际上是悬空的。

你不能使用多态性来产生合适的数组吗?

【讨论】:

【参考方案2】:

您可以使用模板将 DerivedClassV1 值传递给 BaseClass。但是这些值必须是静态常量,所以它们在基类之前被初始化。

#include <iostream>
using namespace std;

void print_array(const uint16_t *array, uint16_t size)
    cout<<"[ ";
    for(int i=0; i < size-1; i++)
      cout<<array[i]<<", ";
    
    cout<<array[size-1]<<" ]"<<endl;



template <class T>
class BaseClass 
protected:
  std::string id_;
  const uint16_t *cat_mapping_ = T::cat_map_;
  const uint16_t *dog_mapping_ = T::dog_map_; 
  uint16_t combinations_;

public:  
    BaseClass(string id)

        cout<<"Base Constructor"<<endl;
        id_ = id;
        combinations_ = T::num_cats_*T::num_dogs_;
        cout<<"Num cats: "<<T::num_cats_<<endl;
        cout<<"Num dogs: "<<T::num_dogs_<<endl;
        print_array(cat_mapping_, T::num_cats_);
        print_array(dog_mapping_, T::num_dogs_);
        cout<<"Combinations: "<<combinations_<<endl;
    

    virtual ~BaseClass();
;


class DerivedClassV1 : public BaseClass<DerivedClassV1> 

public:
  static const uint16_t num_cats_ = 10;
  static constexpr uint16_t cat_map_[10] = 31, 15, 20, 32, 13, 25, 19, 16, 28, 23;
  static const uint16_t num_dogs_ = 8;
  static constexpr uint16_t dog_map_[8] = 5, 25, 23, 4, 13, 15, 14, 26;

public:
  DerivedClassV1(string id) : BaseClass(id)
    cout<<"Derived Constructor";
  
;
constexpr uint16_t DerivedClassV1::cat_map_[10];
constexpr uint16_t DerivedClassV1::dog_map_[8];

【讨论】:

以上是关于使用 C/C++ 中的派生类成员变量将参数传递给 Base 构造函数的主要内容,如果未能解决你的问题,请参考以下文章

如何将参数传递给 draw() 方法 - FLTK

将实例变量作为参数传递给同一类中的方法?

将参数传递给基类构造函数

Boost python将命名参数传递给成员类

将非静态成员函数作为参数传递给另一个类中的成员函数

有没有办法将命令行参数传递给自定义入口点(C / C ++)