Как вызвать соответствующий конструктор - PullRequest
7 голосов
/ 24 мая 2019

Почему я не могу вызвать соответствующий конструктор для объекта Geometry?

class Geometry {
private:
  float fRadius;
  int iSegments;
  float fWidth;
  float fLenght;
  std::string stdstrType;
  bool bValid;

public:
  Geometry() {
    // Set data Elements
    qDebug() << "Constructor 1 is called";
  }

  Geometry(float Radius, int Segments, float Width, float Length,
    std::string strType, bool bValue) {
    // Set data Elements
    qDebug() << "Constructor 2 is called";
  }

  Geometry(const Geometry & g) {
    // Set data Elements
    qDebug() << "Constructor 3 is called";
  }
}

Я использую этот класс как переменную данных в другом классе.

class Container {
private:
  std::string stdstrContainerName;
  std::string stdstrPluginType;
  Geometry Geom;

public:
  Container();
  Container(std::string, std::string, Geometry geometry);
};

Container::Container() {
  stdstrContainerName = "Group";
  stdstrPluginType = "Geometry";
}

Container::Container(std::string strName, std::string strType,
  Geometry geometry) {
  stdstrContainerName = stdstrContainerName;
  stdstrPluginType = stdstrPluginType;
  Geom = geometry;
}

Когда я пытаюсь установить объект Geometry в контейнере, хотя я и дал все параметры для вызываемого конструктора 2, вызывается конструктор 1.

geometry(0.3, 32, 0.0, 0.0, "SPHERE", true);
Container cont("Sphere", "SPHERE", geometry);

Ответы [ 3 ]

9 голосов
/ 24 мая 2019

Что касается вашего варианта использования, вот что вызывает каждая строка:

Geometry geometry(0.3, 32, 0.0, 0.0, "SPHERE", true);    // Geometry constructor 2    
Container cont("Sphere", "SPHERE", geometry);            // Container constructor 2, Geometry constructors 3 & 1     

Здесь конструктор для Geometry на самом деле называется за пределами конструктор Container.Но конструкторы геометрии 3 и 1 также называются ... почему?

Почему так и есть.Поскольку конструктор для Container принимает параметр Geometry по значению, переданный объект geometry будет скопирован (следовательно, вызывается конструктор копирования).Затем в конструкторе Container фактически вызывается конструктор Geometry 1, также известный как конструктор по умолчанию .После этого вызывается функция копирования-присваивания, другой неявно генерируемый специальный метод:

Container::Container(std::string strName, std::string strType, Geometry geometry)
  /*: stdstrContainerName()
    , stdstrPluginType()
    , Geom()*/                    // default-constructors implicitly called as member-initialisation    
{
    stdstrContainerName = stdstrContainerName;
    stdstrPluginType = stdstrPluginType;
    Geom = geometry;              // copy-assignment, i.e. operator= (Geometry const&)  
}

Чтобы переопределить поведение по умолчанию, явно используйте инициализация члена :

Container::Container(std::string strName, std::string strType, Geometry geometry)
    : stdstrContainerName(strName)
    , stdstrPluginType(strType)
    , Geom(geometry)            // copy-constructor, i.e. Geometry(Geometry const&)    
{
}

Это должно привести к конструктору 3, так как теперь вызывается конструктор копирования.

Демо


При переключении на инициализацию члена вы могли заметить, что конструктор 3 вызывается дважды.Опять же, это связано с тем, что конструктор Контейнера принимает свой параметр geometry значением , создавая новый объект посредством конструирования копии.Чтобы предотвратить создание копии и сделать конструктор более эффективным, мы можем передать geometry по ссылке.Кроме того, мы можем установить параметр, чтобы гарантировать, что ссылка не будет изменена в конструкторе.

Таким образом, конструктор Container можно изменить на:

Container(const std::string &strName, const std::string &strType, const Geometry &geometry);    
2 голосов
/ 24 мая 2019

Конструктор Container:

Container::Container(std::string strName, std::string strType, Geometry geometry)
{
    stdstrContainerName = stdstrContainerName;
    stdstrPluginType = stdstrPluginType;
    Geom = geometry;
}

не имеет явной инициализации поля Geom. Сначала он инициализируется по умолчанию, следовательно, вызывается конструктор по умолчанию, а затем вы присваиваете ему аргумент geometry.

Чтобы достичь того, что вы хотите, вам нужно определить конструктор Container следующим образом:

Container::Container(std::string strName, std::string strType, Geometry geometry)
: Geom(geometry)
{
    stdstrContainerName = strName;
    stdstrPluginType = strType;
}

Обратите внимание на : Geom(geometry) часть. Именно здесь вызывается конструктор Geom, и если вы не добавляете что-то подобное в свой конструктор, то вызывается конструктор по умолчанию.

Кроме того, я почти уверен, что у вас есть ошибка в вашем конструкторе. Вероятно, это должно быть stdstrContainerName = strName;, а не stdstrContainerName = stdstrContainerName;. То же относится и к stdstrPluginType.

Еще одна вещь, это не ошибка и технически правильно, но передача объектов таких типов, как std::string или Geometry (то есть объекты, которые могут быть «тяжелыми») может снизить производительность, так почему бы вам не передать их по ссылке? Но это не ошибка (по крайней мере, не в той части кода, которую вы разместили), и она не имеет прямого отношения к вашему вопросу.

1 голос
/ 24 мая 2019

Конструктор # 1 вызывается для аргумента Geometry geometry, передаваемого по значению конструктору Container.Поскольку вы передаете его по значению, он воссоздается в стеке конструктора Container.Измените его на const Geometry& geometry.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...