mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Are you in the same course as monkeybut?

I believe the problem is that the line 45 should be within the for-loop.

I also posted a solution on the thread by monkeybut, but I wouldn't suggest submitting that for your assignment, the prof will be very suspicious if you do.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

There is no technical issue with your code.

But you have some other small issues. First, if you don't intend to return a writable variable, then you should make that member function const (if it is indeed a member function, which is what I assume). Second, returning a pointer is in general not recommended given the fact that a pointer is easily copyable, a reference is preferred. Finally, there is no real point in outputting a reference to such a small type as a double variable, prefer just outputting it by value instead. That would lead to this:

//Either returning a const reference:
const GLdouble& getRotMatrix(int row, int column) const { return rotMatrix[row][column]; };

//Or returning by value:
GLdouble getRotMatrix(int row, int column) const { return rotMatrix[row][column]; };

Both of the above function are virtually the same.

But if you absolutely need a pointer (because you need a pointer for some OpenGL function), then your code is OK (except that you should make the member function const).

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>Sarcasm? I hope. Cause this is c++

No. It's not! C++/CLI is not C++. It's a completely different language and it's more akin to C# than anything else.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Your operator overload defines an operator for Number + int, not for int + Number. Even though mathematically, addition is commutative, the compiler does not assume it is because you could define an addition operator that shouldn't be commutative.

Anyways, to solve the problem, you should define two operators, one for each case. Now, the int + Number version cannot be a member function, i.e., it cannot be a member of the "int" type, so it has to be a free-function. And usually, the other one should too. As so:

class Number
{
 public:
     int value;
};

inline int operator +(Number n, int v) { 
  return n.value + v; 
}

inline int operator +(int v, Number n) { 
  return n.value + v; 
}
Cainer commented: thanks +0
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Turning a loop into a recursion is pretty simple: the body of the loop becomes the function body, and the loop-variable becomes the parameter passed from one recursion to the next.

The loop you have is not the best to lead you into making it a recursion, may I suggest this alternative which is pretty easy to turn into a recursion:

NodeType<ItemType>* traverse = head;
  while(true) {
    if( traverse == NULL ) {
      NodeType<ItemType>* nodePTR = new NodeType<ItemType>(item);
      nodePTR->next = head;
      head = nodePTR;
      length++;
      return true;
    } else if( traverse->info == item ) {
      return false;
    } 
    traverse = traverse->next;
  }

Turning the above into a recursion should be a piece of cake, with those two hints given above.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

May I humbly suggest that you avoid the need to use transcendental functions (log and pow) and those nasty C-style casts by doing this:

void convert_base(int v, int b){
    std::stringstream ss;
    
    do { ss << (v % b); } while( v /= b );

    std::string s = ss.str();
    std::copy( s.rbegin(), s.rend(), ostream_iterator<char>(outputdata) );
    outputdata << std::endl;
}
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>The issue that i am having now is reducing the fractions after they are added/subtracted, etc.

You already have a function to reduce the fraction, why not reuse it by calling it within your operator functions. As so for example:

RationalNumber RationalNumber::operator+(RationalNumber &c) {

	RationalNumber result;

	result.setFraction(((numerator * c.denominator) + (denominator * c.numerator)),(denominator * c.denominator));

	return result;
}

Also, note that you can construct the object with the num / denom parameters directly too, as so:

RationalNumber RationalNumber::operator+(RationalNumber &c) {

	RationalNumber result(((numerator * c.denominator) + (denominator * c.numerator)),(denominator * c.denominator));

	return result;
}

And, then you might as well do this:

RationalNumber RationalNumber::operator+(RationalNumber &c) {
	return RationalNumber(((numerator * c.denominator) + (denominator * c.numerator)),(denominator * c.denominator));
}

hope it helps!

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>i did this but not sure if its what the exercise asks

That looks OK to me, except that your vector should be a vector of integers if you plan to store integers. That is:

vector<int> elements;  //not vector<bool> elements;

Another idiomatic way to fill that vector is using the assign() function, as so:

IntegerSet::IntegerSet(int a[],int size)
{
    elements.assign(a, a + size);  //picks the elements from a[0] to a[size-1].
}

Or, better yet, if you have learned about initialization lists in constructors, then you can do:

IntegerSet::IntegerSet(int a[],int size) :
                       elements(a, a + size) //initializes "elements" with values from a[0] to a[size-1].
{ /* nothing to do here */ }
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

EDIT: sorry double post.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>is there only a constant C++ syntax in the world

Constant, no. Standard, yes. Standards get revised over time, so it's not constant. For C++, the dates to remember are 1998, 2003, and 2011. C++98 is the first ISO standard for C++, anything pre-dating that is "pre-standard" C++ (because the language was drafted and used long before that). Today, you could say that the vast majority of C++ code you see in books or tutorials are in the C++98 syntax (if they are good books or tutorials). The 2003 standard is just a small revision of the C++98 standard, and the differences are not significant (unless you are really advanced or if you are a compiler-vendor). Some extension to the standard libraries have also been introduced, called TR1 (Technical Report 1), which adds some standard features that aren't included in the ISO standard per se (so you might see things like std::tr1::shared_ptr). Then, lately, a new ISO standard is been issued which has be coined as C++0x (because of the hopes of having it release in the late 200x years), but I guess I and many others have to start getting used to saying C++11. That new standard is (almost) entirely compatible with the last one, so that standard C++98 programs are also standard C++11 programs, but you might see additional syntax that might look alien to you if you see a really modern C++ program (like "MyClass&&" or "std::move()" or "auto" and "-> decltype()").


>>there …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>if I were to write a string class and wanted the ability to convert it to an int I would I just have to do this?

Yes.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

@raptr_dflo:
First, thanks for your kind words.

Let me give you a quote of me quoting other people:

"In C++, the preferred channel for signaling exceptional situations is by throwing exceptions. This assertion will not be defended here because it has been discussed at great lengths by most pilars of C++: Stroustrup, Sutter & Alexandrescu, Abrahams, and Cline." -- mike_2000_17 (*)


>>using the tried-and-true method of returning a success/failure indication is preferred

"tried-and-true" well.. that's an over-statement. "Tried" because for a long time there was no alternative. "True" because people eventually managed to _painfully_ make it work in the past.

>>simply because it is more efficient

That's a bold statement, and I have never seen empirical evidence to support that claim, which is usually made on theoretical grounds (like the arguments you put forth). In reality, it seems that the difference between efficiency in error-codes and exceptions is very non-trivial and depends highly on the application and how it is used. But one thing is for sure, there is no clear winner on the efficiency side of things.

>>doesn't need to be error-handled through each intervening function

Yes. When you have a dedicated channel provided by C++ for error-handling, it's just stupid not to use it. This begs the question: What's the difference between the overhead of having an exception channel setup and that of having a channel of …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>a + b would be a.operator+(b) but then how can 5+b be 5.operator+(b) since 5 is a int.

You're wrong. Although you can make an overloaded operator as a member function (i.e. a.operator+(b)), that's not the preferred way, normally it is implemented as a free-function. As so:

// this will cover the ( a + b ) case:
Element operator + (const Element& a, const Element& b);

// this will cover the ( 5 + b ) case:
Element operator + (int a, const Element& b);

// this will cover the ( a + 5 ) case:
Element operator + (const Element& a, int b);

Overloaded operators should almost always be implemented as (friend) free-functions, not as member functions. The only exception to that rule is for the operators that cannot be implemented as free-functions, like assignment operators and a few others.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Wow, LazyFoo seems to be quite an idiot when it comes to licensing issues. So, he basically says:

1) Closed-source, commercial or not: OK to use his code.
2) Open-source, commercial: OK to use his code (with credits given).
3) Open-source, free: Not ok to use his code.
4) Tutorial or demo: Not ok to use his code.

Most licenses are structured entirely the other way around, i.e., any commercial use requires agreement and some licensing deal, and any non-commercial use requires only proper credits given to the original author (and possibly a copy-left clause). His "licensing" policy makes no sense.

Also, remember that he, as the author of code, only has license rights on what is original in his code. Simple functions that just use a few SDL calls to setup something are not his intellectual property because that's just a normal use of the SDL API. So, like most basic programming tutorials that show basic well-known code snippets, those codes are not the intellectual property of the tutorial writer, they are public-domain. Intellectual property applies only to things that have been originally developed (e.g. an original idea, and special new technique developed).

Otherwise, I could write this:

--- Tutorial --- (NOTE: Fictional)
This tutorial will show you how to print "Hello World!" in C++. Here is how:

#include <iostream>

int main() { std::cout << "Hello World!" << std::endl; };

Copyright: 2011 Mikael Persson. Reproduction of the above code …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>So how exactly do you create references?

This will explain it all. Here is a simple example:

#include <iostream>

int main() {
  int a = 69;
  int& ar = a; //declares a reference named 'ar' which is an alias for variable 'a'.
  ar = 42; //assigns the value 42 to 'ar' (which is also 'a').
  std::cout << "the value of a is: " << a << std::endl; //this will print 42
  int* ap = &a; //declares a pointer named 'ap' which stores the address of variable 'a'.
  *ap = 69; //dererferences the pointer 'ap' and stores the value 69 at that variable.
  std::cout << "the value of a is: " << a << std::endl; //this will print 69
  return 0;
};

>>So am I doing the endian-ness stuff right then?

Yes, you are storing the values as little-endian in the file, regardless of the endian-ness of the system. It makes the file-format portable across systems with different endian-ness.

>>Wait, you can actually create code that causes the compile to fail if not used correctly?

Yes, that's the preferred form of error (as opposed to a run-time error). To cause an error at compile-time, the only thing you need is a way to know, at compile-time, whether something is correct or not. Most techniques to achieve this are based on template meta-programming. Often, what you do is that when you create a template (function or class) you can control the instantiation of the template …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>1) The only place I used pointers for was with the reader, which I believe you did as well? If not, can you clarify? This was the only way I could get the reader to work correctly in my code

I used references instead. References are kinda like pointers, but they are not, and are better. References are like variable aliases, i.e. another identifier to denote the same variable, and as such, they lead to a cleaner syntax (no need to take the address and dereference all the time) and they are not reseatable which make them less error-prone. So, no using pointers is not the only way to get the reader to work correctly, using references is the preferred way.

>>Because what if I want to use my file on a separate computer that has a different endianness?

Well, you know what your code does, don't you? Your code essentially makes sure that all data is written to a file in little-endian format. Your write function writes big-endian words in reverse, meaning it is written in little-endian format to the file. Then, your read function reads the little-endian format from the file and reverses it if the system has big-endian. So, that's the point, and that's how you are supposed to deal with endian-ness, that is, you choose one endian format for the binary file and do the conversion on write or on read or both if the system is not in the same endian format.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

That's very nice. It's good to remind people that binary IO does imply worrying about endian-ness.

I do have a few additional caveats and improvements to suggest.

1) On C++ basics, there is no reason to use pointers in this case, passing-by-reference would be cleaner and safer.

2) Your use of the std::ofstream and std::ifstream classes is a bit problematic. The first problem is that you obviously don't need the stream to be a file-stream, so you should use the more general classes of std::ostream and std::istream . The second problem is that your read/write functions are assuming that the stream in question is prepared for binary IO (i.e. opened with the ios::binary flag), this is the kind of "externalized responsibility" that can lead to robustness problems (i.e. you cannot guarantee that the execution of your read/write functions is predictable, because it depends on an external assumption). C++ solves this problem with classes that allow you to protect your invariants, and allow you to not make any assumptions that could be dangerous.

3) A simple issue is your use of sizeof(buffer.b[x]) , this is OK, but is also guaranteed by the C++ Standard to always output 1, so you don't need to use sizeof() there.

4) You should not rely on a in-code definition of your ENDIAN pre-processor flag. Most compilers have standard pre-processor flags to indicate the endian-ness of the environment for which the code is being compiled. For example, for compliance with both …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

You should check out two libraries that are very nice for doing this, the Boost.Program-Options and the Boost.Serialization.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

It is quite easy to check the validity with C++'s formatted input mechanism, which will fail if the input is not of the required format.

Personally, I don't like to fiddle around with the std::cin too much, so I would recommend the intermediate use of std::stringstream.

Something like this would do:

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main() {

  int value = 0;
  while(true) {
    cout << "Please enter an integer number: ";
    string tmp;
    getline(cin, tmp);
    if( stringstream(tmp) >> value )
      break;
  };
  return 0;
};
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

SDL is written in C, so I very much doubt that anything is derived from anything since inheritance in not possible in C. And, yes, SDL_surface is a structure, here is the doc.

Very often (but not always), you should treat SDL_surface pointers and any other pointers from SDL as "opaque pointers", meaning that you should not worry about what it actually points to, that's for the SDL library to worry about. This is similar to windows HANDLE type. Essentially, you should never have to manipulate an opaque pointer yourself, you just get it from SDL functions, then keep it and use it only with other SDL functions. SDL is made such that this is what you should do, but you can also access some low-level information via the fields of the structures like SDL_surface, but for the most part you shouldn't really have to.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

It's a classic problem with class templates and friend functions.

Basically, the problem is that the friend-function declaration declares a function, not a function template. So, when you instantiate the class List<int> , the compiler will instantiate all the member function declarations (not their definitions). The instantiation of the friend-function declaration registers with the compiler that there is a function with this prototype:

ostream& operator << (ostream& os, const List<int>& s);

Which is NOT a function template, just a regular function.

So, when you provide the definition of this function template:

template <class T>
ostream& operator << (ostream& os, const List<T>& s) {
  //...
};

The compiler just sees this as an _overload_ of the friend-function. And, because regular function always have priority over function templates when doing argument-dependent look-up (ADL) of function overloads, the compiler always selects to call the friend-function (because it is not a function template). Finally, since you don't have a definition for that function, the linker complains with a "undefined reference" error because it cannot find the definition of that function anywhere.


So, how to fix it? Here are three options in order of preference:

Option 1: Avoid making a friend-function. In most cases, there will be very little difference between using only public member functions to implement your free-function, and using a friendship relation to access the private/protected data members. Especially considering that all the member functions of a class template can be inlined by the …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The first version contains two overloaded functions (each being a function template). The second version is a template specialization for T = string. However, in your first version, there is no way to deduce the type T from the calling context of the second function template, so you will have to provide that template argument explicitly, which will either make it not really an overload, or make it ambiguous with the first function. Anyhow, the first version will not really work, and the second version is generally not recommended.

The rule is to always overload function templates, never specialize them. That's because ADL has weird interactions between function overloading and template specialization, and there is generally nothing you can do with specialization that you can't do with overloading (or class template specialization).

In your specific case, the following is the preferred option:

//function template for dispm for any type T.
template <class T>
void dispm(T array) {
cout << "called template<class T> void dispm(T array)";
}

//function overload for dispm that takes a string parameter.
void dispm(string array) {
cout << "called void dispm(string array)";
}

For more info, just read Herb Sutter's article on the subject.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

There's nothing wrong with that code. Try to post code that reproduces the error you are experiencing.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Yes, of course. In KDevelop it is called a "session" which can contain as many projects as you like. I don't really know how to configure it and all since I use cmake for my build-configuration, which KDevelop supports very well. So, at least, when I am in KDevelop and have my cmake build-tree loaded, I can easily browse the "projects" in the build-tree (i.e. all the static libs and applications sorted by folder and can easily build all or some of them).

I believe you just "start a new session" and then add projects with Project/New.." and so on.

But, generally, as always, with any IDE, I would recommend to use a IDE-agnostic build-system, like cmake, or make, or qmake, or autoconf, or bjam, etc... Don't bound yourself to a single IDE, get used to "real" build-configurations. And for KDevelop, the choice is obviously cmake.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Your deep-copying is essentially correct. But you are really complicating things by not using the std::string class instead of char-arrays. Always prefer using RAII classes when they are available.

I also recommend you read my tutorial on building a RAII class.

As for your code:

Line 10 is useless.

Line 15 is incorrect. It should be delete[] ptr; because the ptr points to an array.

Line 41 is useless. This line just creates a temporary local variable that is called "ex" and that is never used. Your compiler should complain with a warning about an unused variable, if not, I remind you that you should always compile with the highest possible level of warnings (-Wall on GCC).

You have a lot of constructors, and most of them don't initialize all the data members. Even if you wish to default-construct a data member, you should make that obvious by putting it in the initialization list anyways.


With all those changes in mind, you should get this:

class Bullet {
  private:
    int x, y;
    int dx, dy;
    int startingX, startingY;
    std::string name;

    Extra ex;

  public:
    Bullet();
    //~Bullet(); //destructor not needed because all members are RAII.
    Bullet(const std::string& aName);
    Bullet(int startX, int startY, int moveX, int moveY); //

    //copy-constructor and assignment are not needed because all data members are RAII.
	
    int getX();
    int getY();
    int getDx();
    int getDy();
    int getStartingX();
    int getStartingY();

    void move();
    void show(SDL_Surface*, SDL_Surface*, SDL_Rect);

};

Bullet::Bullet() : …
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Well, you sort of have it correct (with those three functions).

But, in general, the rule is if two functions are the same, they should be one, if two functions are different they should be two. However, with your limited knowledge of C++, you have limited means to implement this. The usually way to deal with this is like the STL algorithms do it (like std::copy). Usually all kinds of containers (arrays, vectors, lists, etc.) can, in most cases, be abstracted as an iterator to the beginning and end (one elements past the end) of the range. That usually allows you to write one function that can deal with any kind of container with just one function. But you need to know about templates. So, be patient with the whole "what's the best way to do this.." line of questioning, it may lead you beyond what you can currently grasp.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>Is it better practice to use an overloaded function vs passing two data types to the same function at once?

Overloading the function. Otherwise, you need an overload for every possible pair of data types or multiple combinations, that's not scalable.


I think a more pertinent question is: Is it good practice to have two data structures that contain the same information? NO. If neither of two data structures are good for your purpose, make your own, but don't keep two data structures in parallel.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

What are you pushing on the stack? If you are just modifying what the char-pointer points to, then yeah, it will change all the stack entries. Try with std::string instead of char-pointers. As in:

int i = 0;
int arraySize;
std::string stack[100];

void stackPush(const std::string& pushed)
{
    if(i == 100)
    {
        cout << "ERROR: Stack overflow!";
    }
    else
    {
        stack[i] = pushed;
        for(int x = 0; x <= i; x++)
        {
            cout << stack[x] << endl;
        }
        i++;
    }
}
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Didn't you think it was important to mention that C++ also implements the AND and OR operators as short-cut operators, that is, if evaluating the first expression is sufficient to get the result of the boolean operation, then the other operands are not computed.

For example, here's a little question:

#include <iostream>

int main() {
  int i = 0;
  bool b = i++ && ++i;
  std::cout << "the value of 'i' is: " << i << std::endl;

  i = 0;
  b = ++i && i++;
  std::cout << "the value of 'i' is: " << i << std::endl;

  i = 0;
  b = i++ || ++i;
  std::cout << "the value of 'i' is: " << i << std::endl;

  i = 0;
  b = ++i || i++;
  std::cout << "the value of 'i' is: " << i << std::endl;

  return 0;
};

What's the output?

(BTW, that's actually a pretty good exam question in a basic C/C++ course)

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

My eagle eye has spotted this at line 43:

else if (line [i] = top ( stack ))

Are you sure you want a single equal sign there? I'm pretty sure you don't.

If I had a dime for every time I see this, I'd be a rich man.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Disregard what Scholl-R-LEA just said. This loop is correct:

while (in_stream >> number)

In fact, the above is the idiomatic way of reading from a file and it is correct. The operator >> does indeed return a reference to a istream, such that it can be chained. However, the istream type is implicitly convertible to a (void*) type which is only NULL (which then converts to "false") if the istream object is no longer in good condition for input (e.g. hasn't reached the end-of-file marker for example).

The reason you get garbage in the "array" is because you call the print function before you call the load function, so "array" is still uninitialized when you print it.

The reason you get 0 in the vector is because, again, you call the print function before you call the load function, so the vector is filled with zeros because that's what you construct it with (default fill-value is zero).

Just put line 42 before line 40-41 and you should get what you expect.

However, there are some additional issues.

First, your function prototypes should not be in the body of the main() function. I'm not sure why your compiler accepts it or if it should (but I don't think it should). You should declare your functions outside the main() function, that is, before it. So, you should put lines 8 to 11 before line 6.

Second, your code is not safe. What if there are …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>someone mentioned that there is a managed C++ that compiles first to Microsoft CLR.

That is called C++/CLI. It is not really C++, it is a completely different programming language if you ask me (it is a kind of a frankenstein between C++ and C#). But I know little about it. I think any .Net version of Microsoft IDE's for C++ will allow you to create a "C++/CLI" project. But it is different from a C++ project.

>>Is using Visual C++ enough to ensure I use this "Managed C++".

No, you have to specify when doing a new project that it is a Managed C++ or C++/CLI project. I'm not sure that just "Visual C++" has that option, you might need a "Visual Studio .NET" version.

>>Does this mean I don't have to worry about destructors?

Managed programming languages have either no destructors (like Java) or destructors that are useless. In pure C++, and using the RAII idiom, the destructors are not something to "worry about", they are something to use. Because C++ has automatic value-semantics, it has a predictable and reliable mechanism of construction / destruction of objects, and thus, you can make great use of destructors to manage your resource acquisition and release code to produce robust and effective code. In managed languages, you have to give up automatic value-semantics and replace it with reference-semantics (in order for garbage collection to work), and at the same time, you lose predictability and reliability of …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>how many instances of the static test t are getting created.

One.

>>What will happen?

Add this to your code:

if( ( &a.t == &a.t.t ) && ( &a.t.t == &a.t.t.t.t.t.t ) )
    cout << "All test t instances are the same!" << endl;

This is just due to two things: a static data member is "globally unique" to the class; and a static member can be access either through "my_class::my_static_member" or "my_object.my_static_member". So, the a.t just accesses the static member of the class, and since a.t is also of the class "test", accessing a.t.t also accesses the same static member, and so on for a.t.t.t, ad infinitum.

The reason why it is allowed to have a static data member of the same class as the containing class is because, since it is static, it is not required to build an object of the class. By opposition, the following code will not work:

class test {
  test t;
};

This is not possible because in order to construct an object of class "test", it requires an object of class "test", this is not possible (i.e. a sort of infinite recursive paradox). So, the compiler would complain saying that "t" is an invalid data member because it is of an incomplete type. When the data member is static, then it is not required to construct an object of that class, so there is no paradox, it works and the compiler allows it because …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The problem is not with what you are compiling but how you are compiling it. Please tell us how you compiled this code (what OS, what compiler, what compiler command or build configuration, etc.).

EDIT: Oups, sorry, didn't notice the two pi variables. That's probably the problem.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>But can anyone testify to it's running native looking GUIs on each of the three main OSs using the same code file?

Yes. Just google for screenshots of Qt-based applications. Pretty much any GUI tool produces "native looking" GUIs, because they are all wrapping native OS calls and constructs.

And yes, these will all be produced by the same code files (and the same GUI files, which are files produced by the GUI designer to define the design of the user interface (Qt uses the .ui extension for those files)).

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

I'm surprised Narue didn't catch this, I guess goddesses are not infallible...

The error is due to the fact that you are trying to separate the function definitions from the function declarations of a class template. Templates are special in C++, they are not real compilable code, they are instructions to the compiler on how to generate code for a given template argument. So, if you try to compile the function definitions separately, the compiler has no template argument to substitute and produces no compiled code for those functions. It has to be that way because the compiler cannot foretell what types you will give as argument to the template in the future.

Anyways, long story short, you cannot separate the function definitions from the function declarations for class or function templates, and thus, you need to put the function definitions in the header file in which they are declared (either inlined or just below). So, the code you have in double_linked.cpp should be put at the end of the double_linked.h file (not completely at the end, of course, within the header guards).

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Why don't you program your UI in C++ and with a cross-platform GUI tool, like Qt. Qt will work everywhere. You most probably want to do your Windows coding in GCC to make sure it will compile with no problems on other OSes. Also, focus on using cross-platform libraries for anything else you might need, like threading and networking. The Boost libraries are very good for that. I also recommend you use a cross-platform build system, Qt more naturally uses qmake, but you can also use cmake.

You will need to have access to both a Mac and a Linux PC to check if your program works there, but you just need that to compile your program once it is almost complete. As long as you never use OS-specific libraries, there shouldn't be any problems. Macs are also fairly close the *nix systems.

If you have a PC, you can easily install a Linux distribution on a USB key and boot from the USB device and you will be able to test your code on Linux that way if you don't want to permanently install a Linux distro on your computer's hard-drive.

To really compile code for Mac, from a PC, you need to setup a cross-compilation. That's not an easy task in general, and I don't recommend doing it (cross-compilation is more typical when you compile for a system on which you wouldn't be able to compile anything …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

@shellexecutor: Don't bump 2 year old threads (the OP probably doesn't care anymore), and don't provide fully working code, especially for such a classic homework problem (pascal triangle) and when the OP didn't show much effort of his own.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Its a linking error, you must have forgot one source file in the compilation. The error means that the function definitions are not found by the linker. Those should normally be in the source file that correspond to the header in which these functions are declared, but you need to compile that source file along with your other source files in order for the linker to be able to find those function definitions.

If you have more trouble with solving this, just describe the split of functions between headers and sources, and how you are compiling them, and we can help.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>how would I do the modulus part?

Well, lets say you want to draw triangles which are 5 characters wide (4 characters of the triangle and one empty column). But if the COL number might be larger than 5, and thus, several triangles could fit along the width. Then if you want to know how many triangles will fit, you can use the integer division, which discards the remainder of the division:

int numberOfTriangles = COL / widthOfOneTriangle; //if COL == 22 and widthOfOneTriangle == 5, you will get numberOfTriangles == 4  (i.e. only 4 triangles fit entirely in 22 characters).

If you want to iterate through the column and know at which position you are in the current triangle you are in, then you can use the modulus (which gives you the remainder of the division only), as so:

for(int i = 0; i < COL; ++i) {
    int positionInTriangle = i % widthOfOneTriangle;  //if i == 18 and widthOfOneTriangle == 5, you will get positionInTriangle == 3  (i.e. the greatest multiple of 5 that fits in 18 is 15, and 18 - 15 = 3).
    // now use positionInTriangle to determine whether to print ' ' or '*'.
  };
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>so I need _native_ , OS independent functions.

If you expect that the C++0x thread library will be native code, you are greatly mistaken. Threading models are a feature provided by the OS (e.g. doing multi-threading on Linux or Windows is very different, whatever library you use). If you are implementing a basic operating system, then making a threading library is one of your tasks, you won't find a native library for threading that doesn't require having an operating system of some kind running. The C++0x threading library, like the Boost.Thread library, are just OS-independent in the sense that the way you use the library is exactly the same from one OS to another, but the underlying implementation relies on the OS features and kernel calls.

You do understand that compilers you can use to compile an operating system to run on a computer natively have libraries that are very different from typical standard library implementations, and are more limited, because most of the things that you take for granted are accomplished by the OS kernel (like dynamic memory allocation, threading, file IO, any other kind of IO, etc.). Standard C/C++ library implementations are provided for an OS and rely on that OS to provide the features it provides, so these are not _native_ functions.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

GCC does not fully support the multithreading libraries or language features yet. See this. The main problem is that the threading libraries make most sense when the language features for concurrent programming are also available, and these are probably the hardest of the new language features to implement.

I recommend you use the Boost.Thread library in the mean time, it's almost identical to the C++0x threading library.

If you are interested in using C++0x, I also recommend you keep your GCC compiler up-to-date, I mean, really up-to-date. Right now, 4.6.2 and 4.7.0 are good versions for C++0x support, but you pretty much have to compile them from source (I do that every month or so). You might also want to check out my tutorials here and here.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

ptr is a pointer to a pointer to a variable. That expression dereferences twice to get the actual variable.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Why don't you read the instructions yourself?

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

You cannot directly link to a DLL like that, as the error says.

To link to a DLL, you can do it either statically or dynamically.

Statically, you need an "import library" (or "interface library"). This is a .lib file that acts as an intermediate between the linker of the compiler suite and the DLL file. Developments suites like MinGW provide tools to generate a .lib file from a DLL. With MinGW, you can use the dlltool program to do that. I don't know about MSVC though, I'm sure there is an equivalent, or that the MinGW dlltool program might produce a .lib file that is compatible with MSVC too.

Anyhow, you have to create the header file manually, and don't forget the extern "C" specification on your function prototypes. You include the header file that you have created for the DLL, and then you link to the .lib file and make sure the DLL is available at run-time for the application (either in the same folder or installed in a standard system folder (usually "C:\Windows\system" or "C:\Windows\system32").


Dynamically, you can use LoadLibrary / GetProcAddress / FreeLibrary (or dlopen / dlsym /dlclose under *nix systems) functions to load the DLL (at run-time), get the function pointers to the functions you have in the DLL, and unload (or free) the library once you are done using the functions of the library (i.e. before exiting the program).

In both …

Ketsuekiame commented: Perfect explanation +8
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

For GCC, you can compile with the options -pedantic-errors -std=c++98 to tell GCC to compile the code in strict standard C++ code (standard from 98, which is current) and to produce compilation errors if you do anything that is not strictly standard C++ code (i.e. pedantic). It is not a perfect option, it might leave some things, but I don't think that a simple piece of homework assignment code would really cause trouble when switching compilers. Technically, if your code compiles fine with the options above under GCC, there should not be any problems compiling with the visual studio 2008 compiler (referred to as MSVC8).

You should also, if your prof didn't tell you already, always compile your code with the highest possible warning levels and treat the warnings as errors. Under GCC, all warnings are enabled with the -Wall compiler option.

In Code.Blocks, to change the compiler options, you should be able to find a place to input "additional compiler options" in the build or project properties/preferences menus.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Like sfuo said, the || and && operators are for boolean values, so, you need to put two conditions (or expressions that evaluate to a bool value) on the two sides of those operators. In this case while(random != 0 && random != 1) , which reads as "while 'random' is not 0 and 'random' is not 1".

It is also good to know that the || and && operators are also short-cut operators. It means that, for example, if the first condition already evaluates to true in a or-statement, the second condition will not be evaluated at all because it is not needed to get the result of the overall expression. Similary, in a and-statement, if the first condition evaluates to false, then the second condition is not evaluated at all. This can be very useful, for example, to check if a pointer is NULL before dereferencing it:

while (ptr != NULL && *ptr != some_value )

The second condition *ptr != some_value will not be evaluated if the first one is false (meaning that the pointer is NULL, in which case you couldn't dereference it).

sfuo commented: Good to know about the pointers +8
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

It is important to remember that MACROs and #defines completely ignore namespaces and are thus very prone to name-clashes if used carelessly.

So, the convention that is the most wide-spread in all C/C++ development is to use all uppercase for MACROs and #defines. This serves as a clear separation between what is under namespace and other scoping rules, and what is not. Also, it is typical and recommended to prepend a "namespace" to the MACROs and #defines, like so:

#define MY_LIBRARY_SQUARE(x) x*x

This is to make sure that your SQUARE macro doesn't conflict with some other library's SQUARE macro (in case one exists and doesn't have a more unique name).

>>But generally that doesn't matter.

I beg to differ. I, like most programmers, want to know for sure which things are MACROs and which are functions, which are #defines and which are constants. This convention of all uppercase is probably the one and only convention that everyone obeys without exception. I do think it matters. Of course, it doesn't matter to the compiler's pre-processor whether you use all uppercase or not, but it matters to every single C/C++ programmer out-there who might be looking at or using your code.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Learning to use command-line arguments is definitely part of the basic things you just need to know, even if you have other practices yourself.

As for command-line vs config-file, why not use both? See the Boost.Program-Options library.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>Moreover, for the containers, if an new obejct is added to them, the copy of that obecjt is also allocated in the heap too?

Yes, but containers like vector and deque for example, use methods to avoid having to reallocate memory on the heap again and again. Vector will preemptively allocate more space than necessary (in an exponential way) in anticipation of future additions of elements.

You have to understand that what is most expensive is the actual allocation and deallocation operations. So, the point is mostly to avoid frequent allocations/deallocations (especially in a loop). Static memory allocations (on the stack) are free (basically no overhead at all), while dynamic memory allocations (big or small) are always pretty expensive operations.

>>So it is not bad to allocate in heap. Is it right?

Consider allocations on the heap as a necessary evil, literally. It is necessary in many cases, but it has big penalties that you always want to avoid if it is not necessary to use it. So, it IS bad, but it IS sometimes necessary.

>>However, I know that malloc() is optimized for medium and large object.

Size matters in non-trivial ways, really. And anyways, malloc should not be used for objects anyways, only for (arrays of) built-in types, because malloc is a C function and will not call constructors of objects. When you talk of size, you really mean the overall size of the memory allocation. Allocating large blocks can be very …