Undefined references -Triangle Comparer

Pages: 12
Most of this I have not written. The only part I am supposed to add things to is Triangle_main.cpp, anything under the TODOs are part of my assignment. I am getting undefined references to Triangle::SetHeight/SetBase/GetArea class member functions and I have finally lost my sanity trying to figure out what I have written that is wrong. I am posting the other .h and .cpp files that go with this.

Triangle_main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include "Triangle.h"
using namespace std;

int main(int argc, const char* argv[]) {
   Triangle triangle1;
   Triangle triangle2;

        double userBase, userHeight;
   // TODO: Read and set base and height for triangle1 (use SetBase() and SetHeight())

   cin >> userBase;
   cin >> userHeight;
      triangle1.SetBase(userBase);
      triangle1.SetHeight(userHeight);

   // TODO: Read and set base and height for triangle2 (use SetBase() and SetHeight

   cin >> userBase;
   cin >> userHeight;
      triangle2.SetBase(userBase);
      triangle2.SetHeight(userHeight);

   // TODO: Determine larger triangle (use GetArea())

   cout << "Triangle with larger area:" << endl;

   if ( triangle1.GetArea() < triangle2.GetArea() ){
    cout << "Triangle 2" << endl;

      triangle2.PrintInfo();
      
   }

   if ( triangle2.GetArea() < triangle1.GetArea() ){
    cout << "Triangle 1" << endl;

      triangle1.PrintInfo();
   }

   // TODO: Output larger triangle's info (use PrintInfo())


}


triangle.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

#ifndef TRIANGLEH
#define TRIANGLEH

class Triangle {
   private:
      double base;
      double height;

   public:
      void SetBase(double userBase);
      void SetHeight(double userHeight);
      double GetArea() const;
      void PrintInfo() const;
};

#endif


triangle.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

#include "Triangle.h"
#include <iostream>
#include <iomanip>
#include <math.h>

using namespace std;

void Triangle::SetBase(double userBase) {
   base = userBase;
}

void Triangle::SetHeight(double userHeight) {
   height = userHeight;
}

double Triangle::GetArea() const {
   return 0.5 * base * height;
}

void Triangle::PrintInfo() const {
   cout << fixed << setprecision(2);
   cout << "Base: " << base << endl;
   cout << "Height: " << height << endl;
   cout << "Area: " << round(GetArea() * 100.0f) / 100.0f << endl;
}

Last edited on
I fixed it! It was a CodeBlocks issue. When I ran the code through the ZyBooks(the publisher we are using for my class) compiler it ran just fine.

Now, the ZyBooks editor/compiler does not give you any feedback on your code so clearly I need to use a different source to debug things. Can anyone tell me why I was getting these error messages out of CodeBlocks?

Thank you for reading everyone!
Hello Icebrand,

Some suggestions if you can use them.

Suggestions in the comments.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>

#include "Triangle.h"

using namespace std;  // <--- Best not to use.

int main(int argc, const char* argv[])  // <--- If you are not using the parameters you do not need them.
{
    Triangle triangle1;
    Triangle triangle2;

    double userBase, userHeight;
    // TODO: Read and set base and height for triangle1 (use SetBase() and SetHeight())

    cin >> userBase;  // <--- These 2 statements need a prompt.
    cin >> userHeight;

    triangle1.SetBase(userBase);
    triangle1.SetHeight(userHeight);

    // TODO: Read and set base and height for triangle2 (use SetBase() and SetHeight

    cin >> userBase;  // <--- These 2 statements need a prompt.
    cin >> userHeight;

    triangle2.SetBase(userBase);
    triangle2.SetHeight(userHeight);

    // TODO: Determine larger triangle (use GetArea())

    cout << "Triangle with larger area:\n";  // <--- Prefer to use the new line (\n) over the "endl"s.

    if (triangle1.GetArea() < triangle2.GetArea())
    {
        cout << "Triangle 2\n";

        triangle2.PrintInfo();

    }

    if (triangle2.GetArea() < triangle1.GetArea())
    {
        cout << "Triangle 1\n";

        triangle1.PrintInfo();
    }

    // TODO: Output larger triangle's info (use PrintInfo())


}


In the "Triangle.cpp" file use the C++ version "<cmath>" over the C version "<math.h>".

Andy
Andy thank you for the reply! I have taken some of your points and made some modifications and decided to integrate all of the files into one cpp file. I know this is not what a professional would ultimately use, but in an attempt to understand what you have pointed out this is a little easier, I will break it up again after I get it.

Why do we not use using namespace std;?

and also why is n\ preferred over endl?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
#include <iostream>
#include <iomanip>
#include <cmath>

using namespace std;

class Triangle {
   private:
      double base;
      double height;

   public:
      void SetBase(double userBase);
      void SetHeight(double userHeight);
      double GetArea() const;
      void PrintInfo() const;
};

void Triangle::SetBase(double userBase) {
   base = userBase;
}

void Triangle::SetHeight(double userHeight) {
   height = userHeight;
}

double Triangle::GetArea() const {
   return 0.5 * base * height;
}

void Triangle::PrintInfo() const {
   cout << fixed << setprecision(2);
   cout << "Base: \n" << base;
   cout << "Height: \n" << height;
   cout << "Area: \n" << round(GetArea() * 100.0f) / 100.0f;
}




int main() {
   Triangle triangle1;
   Triangle triangle2;

        double userBase, userHeight;
   // TODO: Read and set base and height for triangle1 (use SetBase() and SetHeight())

    cout << "Please input base of your first triangle:\n";
      cin >> userBase;

    cout << "Please input height of your first triangle:\n";
      cin >> userHeight;

      triangle1.SetBase(userBase);
      triangle1.SetHeight(userHeight);

   // TODO: Read and set base and height for triangle2 (use SetBase() and SetHeight

    cout << "Please input base of your second triangle:\n";
      cin >> userBase;

    cout << "Please input height of your second triangle:\n";
      cin >> userHeight;

      triangle2.SetBase(userBase);
      triangle2.SetHeight(userHeight);

   // TODO: Determine larger triangle (use GetArea())

   cout << "Triangle with larger area:\n";

   if ( triangle1.GetArea() < triangle2.GetArea() ){
    cout << "Triangle 2\n";

      triangle2.PrintInfo();
   }

   if ( triangle2.GetArea() < triangle1.GetArea() ){
    cout << "Triangle 1\n";

      triangle1.PrintInfo();
   }
   // TODO: Output larger triangle's info (use PrintInfo())

}


The code is working quite well now, now I'll see if I can effectively separate it back into its' constituent files. Thank you for the help!
I think I understand why you would use n\ over endl. For high performance code endl would be a terrible thing to use because you are clearing the buffer every time it is used and that would be really inefficient.

Now I supposed I have another question, under what conditions do you want to clear the buffer? If it is to conserve memory how do you know you are using too much of it?
Hello Icebrand,

I did not mean for you to put everything in 1 file, but if it helped then it was worth it. When I put the 3 files in MSVS 2017 it compiled and worked. So I was thinking that maybe in your case you see 3 files, but the ".cpp" for the class functions may not have been compiled and at link time there was nothing to link to. Thus the error that "main" is trying to call a function that did not exist.

I do have Code::Blocks that I can use, but I am not that familiar with it. In the past I do not recall any problems with using multiple files.

I have not tried it yet, but the changes I see in "main" look good.

As for using "\n" over "endl". I do believe there was a time when the 2011 standards did not empty the buffer using "\n". This is based on the MSVS 2015 I was using at the time. When I upgraded to the 2017 version using the 2014 standards the "\n" seemed to work the same as the "endl". I would not call it "for high performance", but making better use of the language.

The bigger part of this comes from what I have read here and accepted as normal.

As for the: using namespace std:: there has been much written here. Also there should be much that can be found in the whole Web.

What it comes down to is that you are putting the entire standard name space in your program and when you compile you are telling to put "std::" in front of every variable and function name to see if it is in the standard name space. If it is then the compiler will use that instead of what is in your program. Quite often this is a problem when a function in the standard name space requires parameters of 1 type and your function has parameters of a different type. So the function call does not match. Also you are likely to get an warning saying the something is ambiguous meaning that the compiler does not know which function you are trying to use.

I look at it this way. In the beginning you have to learn "std::cout", "std::cin" and "std::endl". Next may be "std::string" and "std::getline" and anythinf else that is available in the "string class". Doing this a little bit at a time it is not that hard to learn. The other way is to wait until "namespace" is covered in a class and you would have to learn everything at 1 time. My-self I prefer a little at a time over all at once.

When it comes to clearing the buffer it really depends on your code. Formatted input: std::cin >> aVariable will leave the "\n" in the buffer, but followed by another formatted input it will ignore an white space, which includes the "\n", until it finds something to extract. The other problem you will find is that formatted input will extract from the buffer until it finds white space, usually a space, or "\n" whichever comes first. This tends to work great for numbers, but not when you want to put "first last" into a string. Formatted input will put "first" into the string stopping at the space leaving this in the buffer for the next input to use.

The opposite is "std::getline" or unformatted input. This takes whatever you type and stores it in the variable, which is a "std::string" type variable. It also extracts the "\n", but discards it as the string does not need it leaving the buffer empty.

In the end it depends on your code. Formatted input followed be unformatted input needs the buffer cleared otherwise the unformatted input will read the "\n" and move on thinking it has everything it needs and skipping your input. Unformatted input followed by formatted inpu is not a problem.

As far as to "conserve memory" the buffer used for input or output is already defines and has a size. Whether it contains "\0"s or some other characters makes no difference. Clearing anything that may be in the buffer does not change its original size, so there is nothing to conserve.

Andy
Andy, thank you so much for the explanation, this makes things a lot clearer!
@Icebrand,
Regarding namespace std;
You have probably seen people saying things like std::cout, std::cin, and std::endl;. Well, those are defined in what's called the standard namespace. You'll probably learn more about it if you Google a definition of it, but basically what using namespace std; does is, it tells the compiler that for everything in the standard namespace, just ignore if someone omits the scope ( the std::).

Like this:
1
2
3
4
5
6
7
8
9
#include <iostream>

int main ()
{
	// std:: means "In the standard namespace"
	std::cout << "Hello world!" << std::endl;
	
	return 0;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

// Tells the compiler to automatically use the standard namespace
// on things like cout, cin, endl, string, etc.
using namespace std;

int main ()
{
	// Now it automatically uses the standard namespace.
	cout << "Hello world!" << endl;
	
	return 0;
}


Note: If you are using macOS, I can give you some tips on how to debug C++ programs using the Terminal application.

Edit:
I just noticed that Handy Andy already explained it in his post. Whoops.
Last edited on
@agent max

Your post seems to imply that using namespace std; is better - well it isn't.
@TheIdeasMan,
If you have a huge program with, say, 500 lines, it saves you from typing the std:: before every standard object. I use it all the time.

But I am curious to hear why you say it's not better. Please, explain.

max
closed account (z05DSL3A)
If you have a huge program with, say, 500 lines,

made coffee come out my nose.

But I am curious to hear why you say it's not better. Please, explain.

it's been discussed here a few times.
I don't think I've written a program with more than 200 lines or so, so 500 is huge for me. But I am aware that there are much bigger programs out there. Could you shoot me a link to a thread where it's explained? That would be much appreciated!

Thanks!
max

P.S. Hope you didn't get coffee on your keyboard ;).
Last edited on
closed account (z05DSL3A)
Search terms: Using Declarations, Using Directive, or Full Scope Resolution.

Here are a few...
http://cplusplus.com/forum/general/250849/
http://www.cplusplus.com/forum/beginner/9181/#msg42419
http://www.cplusplus.com/forum/beginner/21249/

The important thing is understanding what is happening with the different things...
Thanks! I guess I didn't really understand what it actually is...but now I do!
@agent max
With background you can understand why using namespace often invites portability issues. Typically the resulting problems result in compilation errors, but in the worst cases a program will compile to contain actual runtime errors.

Feel free to use it habitually if you enjoy telling your customers "but it works on my machine" while fixing your broken software. Otherwise, think about it first: there are cases where using namespace is quite risk-free.
Last edited on
Well, I don't write code for other people, so that's not going to be an issue. But thanks for setting me straight!

It's hard to believe that my Computer Sci professor just told us to use it without even explaining what it was or that it could cause problems.

max
@agent max

also search the term MLOC

There are people here who deal with programs that are 100 MLOC. I have heard stories about code that takes 24hrs to compile ! To put that into perspective, if compile the latest version of gcc with all the languages gcc can do, on my machine that takes about 1 hr

A long time ago I read that Excel, Word etc were about 1 MLOC, not sure how true that is these days.

Writing std::copy is explicit, whereas copy is not: is it boost::copy or some other copy from some other place you don't know about yet? The compiler might find an unexpected version.

The other thing that is convenient, is to use a namespace alias:

https://en.cppreference.com/w/cpp/language/namespace_alias

This allows for a longer name for the namespace, and a shorter abbreviation for it in the code.

Prefer to organise all of your own code into namespace/s.
It's hard to believe that my Computer Sci professor

In this case your customer is your TA or professor, whoever grades your work.
closed account (z05DSL3A)
Prefer to organise all of your own code into namespace/s.

I have just been pondering if it is better to put using namespace std; in an unnamed namespace or not (if you were to use it)

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

namespace
{
    using namespace std;
}

int main()
{
    cout << "Hello World!\n";

    return 0;
}


I'm racking my brain trying to remember who/where it was said you should do it.
Holy mackerel! My computer would probably go splat on me if I tried to compile anything that took over a few minutes!

I have never used namespaces before, other than the std:: namespace. But that's really interesting. But what would you use a namespace for, anyway?
Pages: 12