C++: Calling function in main.cpp from another .cpp file

  • C/++/#
  • Thread starter JonnyG
  • Start date
  • #1
227
22
I am trying to call a function declared in a .hpp file and defined in the corresponding .cpp file, from my main.cpp file, but I keep getting an error. From what I have googled it seems as if I am doing this the right way, so I was hoping you guys could help out. Here's my code:

Chap.hpp:
#ifndef CHAP_HPP
#define CHAP_HPP

class Chap
{
public:

double absoluteVal (double n) ;
unsigned fact (unsigned n) ;
};

#endif // CHAP_HPP

Chap.cpp:
#include "Chap.hpp"


double absoluteVal (double n) {
    return (n >= 0) ? n : -n;
}

unsigned fact (unsigned n) {
    unsigned product {1};
    for (unsigned i = 1; i <= n; ++i)
        product *= i;
    return product;
}

main.cpp:
#include <iostream>
#include "Chap.hpp"

using std::cout;
using std::cin;
using std::endl;

int main() {
    cout << "Enter a number: ";
    double n;
    cin >> n;
    cout << "The absolute value of " << n << " is " << absoluteVal(n) << endl;
    return 0;
}

The error that I'm getting is:

C:/Users/J/Desktop/CPP/CppPrimer/CppPrimer/main.cpp: In function 'int main()':
C:/Users/J/Desktop/CPP/CppPrimer/CppPrimer/main.cpp:19:56: error: 'absoluteVal' was not declared in this scope

For what it's worth I am using the CodeLite IDE and a mingw-w64 compiler. I'd appreciate any help. Hopefully it's just me making a silly mistake.
 

Answers and Replies

  • #2
jtbell
Mentor
15,764
4,001
The functions absoluteVal and fact are declared in Chap.hpp as members of the class Chap.

Therefore when you define the functions in Chap.cpp, you need to name them as Chap::absoluteVal and Chap::fact.

Also, when you use the functions in main.cpp, you first need to declare an object of type Chap. Then you can call the functions as members of that object, for example:

C++:
    Chap myChap;
// ... your other stuff
    cout << "The absolute value of " << n << " is " << myChap.absoluteVal(n) << endl;

Disclaimer: I have not actually tried to compile and run your code with these corrections.

I'm curious about why you want to write a class that has member functions but no member data.
 
  • #3
227
22
This works. Thanks.

I'm curious about why you want to write a class that has member functions but no member data.

I am going through C++ Primer. We are going over functions, so I write those two. I was then asked to create a header file with the function declarations in there. But then that got me thinking that I would like to remove my two functions (absoluteVal and fact) from my main.cpp file and put them in a .cpp file that corresponds to the header file I created. We haven't gone over classes in any detail yet. If I wanted to write a function (not a method - I am purposefully making this distinction), is the only way to include it in my main.cpp file? I feel like I may be asking a question for whose answer I may not be ready for yet.

EDIT: I just looked at the table of contents and in the next chapter we are going to cover classes and there is a section titled "defining nonmember class-related functions". I'm guessing that section will have my answer.
 
  • #4
jtbell
Mentor
15,764
4,001
If you want to have separate header and implementation files for plain old functions, then toss out your class Chap from Chap.hpp and replace it with just the prototypes of the two functions:

C++:
#ifndef CHAP_HPP
#define CHAP_HPP

double absoluteVal (double n) ;
unsigned fact (unsigned n) ;

#endif // CHAP_HPP

Then you should be able to use the original versions of main.cpp and Chap.cpp.
 
  • Like
Likes sysprog and JonnyG
  • #5
1,961
1,209
jtbell said:
Disclaimer: I have not actually tried to compile and run your code with these corrections.
That reminded me of this great line from Prof. Don Knuth (creator of ##\TeX##): Beware of bugs in the above code; I have only proved it correct, not tried it.
 
  • #6
jtbell
Mentor
15,764
4,001
Haha, yeah, I was going out on a limb because because it's past my bedtime and I wanted to get to sleep.

But now that I'm hooked on this, I went ahead and set up the files for my suggested version in post #4. The following line in Chap.cpp:

unsigned int product {1} ;

gave me the message error: expected ';' at end of declaration. Looking more closely I noticed the {1} which I've never used for initializing a scalar variable. I've always done it as something like

unsigned int product = 1 ;

I thought, maybe this is something from C++11 and newer? I told my g++ to use -std=c++11, and sure enough it worked. So now I've learned something. :cool:

It makes sense to allow initialization this way, because it's consistent with list-initialization of arrays, etc.
 
  • #7
jbunniii
Science Advisor
Homework Helper
Insights Author
Gold Member
3,473
255
Looking more closely I noticed the {1} which I've never used for initializing a scalar variable. I've always done it as something like

unsigned int product = 1 ;

I thought, maybe this is something from C++11 and newer? I told my g++ to use -std=c++11, and sure enough it worked. So now I've learned something. :cool:

It makes sense to allow initialization this way, because it's consistent with list-initialization of arrays, etc.
Yes, this is called uniform initialization syntax and was added in C++11. https://isocpp.org/wiki/faq/cpp11-language#uniform-init

It's 2020, and C++11 added many very good features that make many parts of the language easier and safer to use. I highly encourage you to always enable it (even better, C++14 or C++17). :smile:

In addition to providing a uniform syntax for initialization (as you noted, and as the name implies), it also has the advantage of disallowing implicit narrowing, so for example, lines 10 and 18 below are disallowed:
C++:
double myDouble {0.1};
uint32_t myUint32 {1};

// Error; assigning double-precision float to a single-precision float.
// Use
//    float myFloat {static_cast<float>(myDouble)};
// or
//    float myFloat = myDouble;
// instead.
float myFloat {myDouble};

// Error; assigning 32-bit integer to a 16-bit integer.
// Use
//    uint16_t myUint16 {static_cast<uint16_t>(myUint32)};
// or
//    uint16_t myUint16 = myUint32;
// instead.
uint16_t myUint16 {myUint32};
A couple of other notes: use of = with uniform initialization syntax is optional, so the following are equivalent:
C++:
int n {0};
int n = {0};
And empty braces provide default initialization, which calls the default no-argument constructor for class types, and zero-initialization for numerical types, so the following are equivalent:
C++:
int n {};
int n {0};
whereas of course this will result in an uninitialized variable, generally containing garbage:
C++:
int n;
 
Last edited:

Related Threads on C++: Calling function in main.cpp from another .cpp file

Replies
4
Views
7K
  • Last Post
Replies
7
Views
3K
Replies
5
Views
16K
Replies
4
Views
2K
Replies
5
Views
883
Replies
1
Views
1K
  • Last Post
Replies
11
Views
6K
  • Last Post
Replies
2
Views
2K
Replies
1
Views
17K
Top