【问题标题】:Declare a global variable without initialising in c++声明一个全局变量而不在 C++ 中初始化
【发布时间】:2019-10-22 05:50:01
【问题描述】:

假设我有一个头文件:

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 文件中的另一个函数中使用它?

【问题讨论】:

  • 我认为这不可能直接。一种解决方法是使其成为全局指针并将指针值分配给 main 中 new 返回的指针值。
  • 虽然,我不会推荐这个。您应该避免使用全局变量。尝试使用面向对象的设计来解决这些问题。
  • @JatinSharma 对于这个项目,我是。我知道这不是一个好方法,但我只是出于好奇而想知道

标签: c++ scope


【解决方案1】:

这个问题混杂了一些东西。我将尝试单独解决它们。


关于默认构造函数的错误信息正是:您要求实例化该类的一个实例,但您只提供了一种方法:带有string 参数的构造函数。

有两种方法可以“直接”处理:

  1. 提供默认构造函数,通过显式设置或使string 参数可选,如my_class(string var1_val = {})
  2. 在实例化时提供上述参数:my_class f{""};

在全局范围内有一个“外部”变量,但在 main()... ):

  1. 使用指针。将您的变量声明为my_class * f{nullptr};,或者更好的是,声明为智能指针:std::unique_ptr&lt;my_class&gt; f;,然后将 main 中的对象实例化为裸指针 f = new my_class("string"); 或智能指针 f = std::make_unique&lt;my_class&gt;("args");
  2. 将该变量设为main() 的本地变量并将其传递给您需要的任何函数

您也可以考虑使用单例模式,其中有一个工厂函数来管理您的 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
}

【讨论】:

    【解决方案2】:

    你描述的问题

    就像下面的代码运行一样,我得到:'my_class':没有合适的默认构造函数可用

    是因为你声明了另一个带有一些参数的构造函数。在这种情况下,编译器不会生成默认构造函数。你必须自己做。所以这个类应该是这样的:

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

    好的做法是,当您使用一个参数创建构造函数时,将其标记为explicit。另一个好的做法是在构造函数初始化列表中分配变量。

    最好的问候

    【讨论】:

      【解决方案3】:

      就这样做

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

      提供默认参数,一切顺利。 只是为了让编译器闭嘴。 虽然使用全局对象并不是一个好的解决方案。

      【讨论】:

        【解决方案4】:

        这不是直接可能的...全局类实例需要初始化(只有像 intdouble 这样的类型可以保持初始化,但只能在本地范围内 - 作为全局,它们总是被初始化 - 这种可能性保留变量未初始化也是许多人认为 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;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-05-09
          • 1970-01-01
          • 2021-10-28
          • 2020-10-30
          • 1970-01-01
          • 1970-01-01
          • 2016-12-17
          • 1970-01-01
          相关资源
          最近更新 更多