0

My IDE is Microsoft Visual Studio 2017.

This is primitive example code:

main.cpp

#include <iostream>
#include "Klasa_00.h"

using namespace std;

int main() {

    int const Number_0 = 234;
    float const Number_1 = 34.76;
    double const Number_2 = 98.78;

    cout << "Number_0 is:" << Number_0 << endl;
    cout << "Number_1 is:" << Number_0 << endl;
    cout << "Number_2 is:" << Number_0 << endl;

    system("Pause");
    return 0;
}

Klasa_0.cpp

#include "Klasa_00.h"

Klasa_00::Klasa_00()
{
}


Klasa_00::~Klasa_00()
{
}

Klasa_0.h file

#pragma once
class Klasa_00
{

public:
    Klasa_00();
    ~Klasa_00();


};

I am new in C++ programing so I need a help about making code. For example, in Fortran programing language all variables with parameter attribute can be declared in separate module which can be easily used in main program. What I want to learn here is possibility of using that principle of coding in C++ or something similar. So, in my case a have a three variables which i want to move into class Klasa_00. Is there way or ways for doing that?

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • Constants like yours can simply be defined in a header file, and then #included wherever you need them. –  Dec 14 '18 at 16:22

2 Answers2

2

As others have said, you might want to avoid using classes to store your constants in other files, and you might simply wish to store them in a header (possibly with a namespace, more on that later). Having said that, I do understand that you might want a constant that belongs to a class, so I'll cover that case as well later in the answer.

The simplest way is to declare and define the constant in a header on its own as such:

// YourHeader.h
#ifndef YOUR_HEADER_H
#define YOUR_HEADER_H

[...]
const int aConstNumber = 1;
static const int anotherConstNumber = 2;
constexpr int aConstExprNumber = 3;
static constexpr int anotherConstExprNumber = 4;
[...]

#endif

// main.cpp
#include <iostream>
#include "YourHeader.h"
int main()
{
    // You can simply access the variables by name as so:

    std::cout << aConstNumber << "\n"; // 1
    std::cout << anotherConstNumber << "\n"; // 2
    std::cout << aConstExprNumber << "\n"; // 3
    std::cout << anotherConstExprNumber << std::endl; // 4
}

These variables all behave the same logically, but they work in different ways. A variable declared with the const keyword is defined at runtime, and guaranties it won't change. A variable declared with the constexpr keyword, however, is defined at compile time.

So, while this means that if you had multiple classes with something like an ID (which shouldn't change, but should be unique), you'd prefer const over constexpr (since the latter wouldn't work in that context).

Let's talk about static as well. static means that there is a single shared instance of that variable across your classes. So if the Bar class has a static int ID value, all instances of Bar share the same ID value. Changing it once changes it for all instances. Though if it's a constant, you won't be able to change it.

In your case, if it's to define constants that are pre-defined and won't change, I'd strongly recommend using constexpr, since you can use those variables to do things you couldn't use a const variable for (like defining the size of an array).

Before you go ahead and do that, however, consider the following class.

class Foo
{
public:
    const int a = 5; // Valid use of const.
    constexpr int b = 7; // Invalid use of constexpr, won't even compile!
    static constexpr int c = 10; // Valid use of constexpr.

    int arrA[a]; // ERROR: 'a' is defined at runtime, so you can't use it to define a size.
    int arrB[b]; // ERROR: You couldn't even define 'b', so this is not going to work...
    int arrC[c]; // VALID: 'c' is known by the compiler, and is guaranteed to only ever be 10!
}

It is worth noting that if you wanted to access a or c (the only two valid variables declared and defined in your class), you'd have to use the following syntax, rather than just their names:

// "Foo" is their class' name, and represents their parent namespace.
std::cout << Foo::a << "\n"; // 5
std::cout << Foo::c << std::endl; // 10

As you can see, constexpr int b = 7; is invalid. Why though? Shouldn't it be seen by the compiler and work just fine? Well, no. You see, the issue is that maybe you'll never instantiate that class, right? const variables are fine, because they're defined at runtime, this means they don't have to exist, they just can't change once you've given them a value. constexpr on the other hand needs to be sure it'll exist, because it has to exist and be valid at compile time!

While declaring a constexpr variable is perfectly fine in a header file, it doesn't work unless you use the static keyword with it if you want to declare one in a class! Because the static keyword will let the compiler know that, regardless of how you instantiate this class, the variable's value will never change and it will be known at compile time thanks to constexpr!

I strongly recommend you read this post to understand just what static and constexpr do when combined.

  • If you have "constants" that are only constant once instantiated, go with const.
  • If you have constants that will never change and will always represent the same value (think of mathematical values like PI) go with constexpr.
  • If all instances of a class should share a constant value, I'd recommend against using static const, since it would be defined at runtime, but it will always have the same value, right? Just use static constexpr instead.

Finally, I mentioned namespaces at the start of this answer. Sometimes, you might want a group of associated constants that don't necessarily belong to a class. For instance, while PI is used in circles, it doesn't necessarily mean that I want to include the circle class' header every time I want PI. But I don't want to have a "raw" PI variable name in my project's namespace! That's just asking for trouble. Instead, consider surrounding your constants in a namespace block to emulate the syntax used to call a class' member!

// YourHeader.h
#ifndef YOUR_HEADER_H
#define YOUR_HEADER_H

namespace MyConstants
{
    constexpr int a = 1;
    constexpr int b = 2;
}
#endif

    // main.cpp
#include <iostream>
#include "YourHeader.h"
int main()
{
    std::cout << MyConstants::a << "\n"; // 1
    std::cout << MyConstants::b << "\n"; // 2
}

Note that we didn't use static with a namespace, we don't need to since we're not using a class or struct, we're simply wrapping them in the namespace to avoid naming conflicts. static would do something else here. See this post for more info on that.

Extra Note: While it is possible to declare a variable as a constexpr const, I wouldn't recommend it as it does the same as simply declaring it constexpr. Do note that constexpr when combined with pointers will turn the pointer into a constant pointer to a constant value! See this post for more details on that.

micka190
  • 742
  • 2
  • 8
  • 20
1

Why do you feel that you need a class for this? That doesn't seem appropriate. FORTRAN comparisons are also not likely to bear much fruit as C++ is a different language with different idioms and concepts.

To me, it seems like you should simply put those constants in a header file. Be sure to make them static const constexpr to avoid linker clashes.

// Constants.hpp
#ifndef MYLIB_CONSTANTS_HPP
#define MYLIB_CONSTANTS_HPP
#pragma once

static constexpr const int Number_0 = 234;
static constexpr const float Number_1 = 34.76;
static constexpr const double Number_2 = 98.78;

#endif

Now you just #include "Constants.hpp" in any translation unit that requires access to these values.

For the record, the old-school C approach to do the same thing would be to use #defines.

Don't forget to give these constants meaningful names.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • They don't have to be declared static. –  Dec 14 '18 at 16:24
  • My intention is to learn also option with class. For example, I want to use class which contains also constant variables. –  Dec 14 '18 at 16:27
  • @Neil: Hmm, fair point. Though personally I still like to leave it in wherever, because the inline linkage isn't inherent if you move these into a class – Lightness Races in Orbit Dec 14 '18 at 16:30
  • 2
    @Judge_Dredd But if you want to learn C++ properly, you won't be creating a class that contains nothing but constants. That's not really what a class is for. You could put them in a _namespace_, and to be fair some people do use a class instead of a namespace, for some reason. I wouldn't recommend it though. If you want to create a class for some other purpose, then that's a different situation and a different question. Which book are you using? – Lightness Races in Orbit Dec 14 '18 at 16:31
  • I also get a warning message: truncation from double to const float. –  Dec 14 '18 at 16:33
  • Well, I will follow your suggestion. I am using now a book: Bjarne Stroustrup - The C++ Programming Language –  Dec 14 '18 at 16:38
  • @Judge_Dredd, to eliminate warning just cast type explicit f.e. `(int)Number_1` – Dmytro Dadyka Dec 14 '18 at 16:48
  • 1
    @DmytroDadyka Probably better to just use the right literal `static constexpr const float Number_1 = 34.76f;` – George Dec 14 '18 at 16:53