Объявите глобальную переменную без инициализации в c ++ - PullRequest
0 голосов
/ 22 октября 2019

Скажем, у меня есть файл заголовка:

class.h

#pragma once
#include <iostream>
#include <string>
using namespace std;

class my_class
{
private:
    string var1;
public:
    my_class(string var1_val) { var1 = var1_val; };
};

Я хочу объявить переменную my_class как глобальную, чтобы ее можно было использовать в функциях. Однако он не может быть инициализирован вне основной функции, так как для инициализации требуется ввод данных пользователем. Это создает проблему, как будто приведенный ниже код запускается, я получаю: 'my_class': no appropriate default constructor available

source.cpp

#include <iostream>
#include <string>
#include "classes.h"
using namespace std;

my_class f;

int main(){
    string inpt;
    cout << "Enter var1 value: ";
    cin >> inpt;
    f = my_class(inpt);
}

Как бы я определить переменную f, чтобы я мог инициализироватьэто в main, но также использовать его в другой функции в файле source.cpp?

Ответы [ 4 ]

2 голосов
/ 22 октября 2019

В этом вопросе смешано несколько вещей. Я постараюсь обратиться к ним по отдельности.


Сообщение об ошибке в конструкторе по умолчанию именно так: вы просите создать экземпляр этого класса, но вы предоставляете только один способ сделать это:конструктор с параметром string.

Два способа, которыми вы можете справиться с этим "напрямую":

  1. предоставляют конструктор по умолчанию, либо явно указав его, либо сделав stringнеобязательный параметр, например, my_class(string var1_val = {})
  2. предоставляет указанный параметр во время создания экземпляра: my_class f{""};

Имеет переменную "снаружи" в глобальной области видимости, но инициализируетсяв main() ... Кроме того, несколько способов справиться с этим (лично я бы посоветовал против такой практики по разным причинам, но предоставляя варианты здесь для полноты):

  1. Используйте указатели. Объявите вашу переменную как my_class * f{nullptr}; или, что еще лучше, в качестве умного указателя: std::unique_ptr<my_class> f; и создайте экземпляр объекта в вашей основной сети как голый указатель f = new my_class("string"); или умный указатель f = std::make_unique<my_class>("args");
  2. , которые имеютпеременная local для main() и передача ее в любую нужную вам функцию в

Вы также можете использовать шаблон Singleton, где у вас есть фабричная функция, которая управляет вашим f (опять же, ужасная идея в данном случае, но для полноты):

my_class & get_my_class(string s = {}){
  static my_class * mc{nullptr};
  if(!mc){ mc = new my_class{s}; } // <-- memory leak here unless you use unique_ptr
  return *mc;
}

int main(){
  // ... 
  auto & m{get_my_class("user input")};
  // ... 
}

void other_function(){
  auto & f{get_my_class()};
  // use f
}
0 голосов
/ 22 октября 2019

Это невозможно напрямую ... глобальный экземпляр класса требует инициализации (инициализируются только такие типы, как int или double, но только в локальных областях - поскольку глобальные они всегда инициализируются - и эта возможностьоставление переменных неинициализированными - это тоже то, что многие считают ошибкой проектирования языка C ++ - большинство младших языков не предоставляют эту опцию, поскольку опыт научил нас, что это источник неприятных ошибок и не дает реального преимущества).

То, что вы хотите сделать, можно интерпретировать как вариацию того, что обычно называют «одноэлементным шаблоном» ... то есть предоставление всем модулям доступа к одному экземпляру класса.

Обычно это делается в C ++используя функцию, которая возвращает ссылку на переменную ... например:

------------------------------------------------------------ parms.h
...
struct Parms {
    std::string user_name;
    int user_age;
    static Parms& get();   // Providing access to the singleton
};

-------------------------------------------------------- module1.cpp
#include "parms.h"
...
void foo() {
    // access the singleton
    std::cout << "Hello " << Parms::get().user_name << "\n";
}

---------------------------------------------------------- parms.cpp
#include "parms.h"
...

static Parms* parmsp;

void init_parms(const std::string& user_name, int user_age) {
    // creates the singleton
    parmsp = new Parms{user_name, user_age};
}

Parms& Parms::get() {
    // Provide access to the singleton
    if (!parmsp) {
        throw std::runtime_error("Parameters not yet initialized");
    }
    return *parmsp;
}
0 голосов
/ 22 октября 2019

Просто сделайте это

my_class(string var1_val="") { var1 = var1_val; };

Укажите аргумент по умолчанию и все готово. Просто чтобы заставить компилятор заткнуться. Хотя использование глобального объекта не является хорошим решением.

0 голосов
/ 22 октября 2019

Проблема, которую вы описываете

, как будто выполняется приведенный ниже код, я получаю: 'my_class': нет подходящего конструктора по умолчанию, доступного

, потому что у вас естьобъявить другой конструктор с некоторым параметром. В этом случае компилятор не будет генерировать конструктор по умолчанию. Вы должны сделать это самостоятельно. поэтому класс должен выглядеть так:

    class my_class
{
private:
    string var1;
public:
    my_class(){};
    explicit my_class(string var1_val) : 
    var1(var1_val)
    {};
};

Хорошая практика - когда вы создаете конструктор с одним аргументом, пометьте его как explicit. Еще одна хорошая практика - назначать переменные в списке инициализации конструктора.

С наилучшими пожеланиями

...