Open Side Menu Go to the Top
Register
SenorKeeed's adventures in C++ SenorKeeed's adventures in C++

04-12-2013 , 06:34 PM
So with

Flight** ptrFlight;

in the header file it then the data field ptrFlight doesn't necessarily have to be an array. Could I also declare it

Flight* ptrFlight[ ];

and have it be basically the same thing but then it has to be an array? Would I be able to use the same syntax in the constructor of

ptrFlights= new Flight*[100]
SenorKeeed's adventures in C++ Quote
04-12-2013 , 06:47 PM
Quote:
Originally Posted by SenorKeeed
if I don't use new in the constructor then it won't it be on the stack instead of the heap? We're supposed to allocate the array dynamically.

I haven't really written the code to test the class yet. I'm just trying to get it to compile.
Only local variables get created on the stack. Member variables get created with the containing class which could be stack or heap depending on the user of the class. You still have to initialize the array in the constructor. The assignment is what it is though, so new the array as required.

You have written far too much without compiling. Start very small. Compile, run. Then add more. You want to always have a working program and then make a small change and see what happens.

I would start by writing the user of the class before there is a class. Add just enough to keep the user happy step by step. So step one:

Code:
#include "foo.h"
void TheUser()
{
Foo* f = new foo();
delete f;
}
That fails, so you have to make a foo.h

Code:
// foo.h
class Foo
{
int dummy; // just so it isn't completely empty.
};
Now TheUser can compile. Keep making small changes. Have TheUser call a method. That fails. Add an empty method declaration to foo.h. Now TheUser can compile but not link. Add a foo.cpp that contains the definition of the method (don't let the method do anything yet). Now it works again.

This is the cycle. You have something that works but is incomplete. You add the minimum part of a feature. It doesn't work. You add what's needed to make it work again.

Adjust the names to fit your problem.

Yes, I'm saying start over.
SenorKeeed's adventures in C++ Quote
04-12-2013 , 07:05 PM
Quote:
Originally Posted by Chips Ahoy
Only local variables get created on the stack. Member variables get created with the containing class. You still have to initialize it in the constructor. The assignment is what it is though.

You have written far too much without compiling. Start very small. Compile, run. Then add more. You want to always have a working program and then make a small change and see what happens.
Oh no, I have been doing that. It was working OK until I tried to simply my functions by adding a numberFlights field rather than have each function check the length of the array each time it was called. Somehow that screwed everything up because I had declared ptrFlights incorrectly.

Quote:
Now TheUser can compile. Keep making small changes. Have TheUser call a method. That fails. Add an empty method declaration to foo.h. Now TheUser can compile but not link. Add a foo.cpp that contains the definition of the method (don't let the method do anything yet). Now it works again.

This is the cycle. You have something that works but is incomplete. You add the minimum part of a feature. It doesn't work. You add what's needed to make it work again.

Adjust the names to fit your problem.

Yes, I'm saying start over.
OK, you were asking me for my test code, I thought you meant like what I would eventually be doing for my main function once I had the classes all working right. Here's what I have so far, I just keep adding lines that test what I'm trying to do in the functions, more or less what you're advising I think:

Code:
#include "Passenger.h"
#include <iostream>
#include <string>
#include "Seat.h"
#include "Flight.h"
#include "Airline.h"

using namespace std;

int main()
{
  string myName="Matt";
  string myDeparture="Boston";
  string myDestination = "Detroit";

  Passenger p(myName,myDeparture,myDestination);
  myDestination="San Franscisco";
  p.setDestination(myDestination);
  cout << p.getDestination() << endl;
  string StatusA="Available";
  string StatusR="Reserved";
  string StatusS="Sold";
  Seat seat1(10,StatusA,1);
  cout << seat1.getSeatNumber() << endl;
  cout << seat1.getStatus() << endl;
  cout << seat1.getAvailability() << endl;
  seat1.setStatus(StatusS);
  cout << seat1.getStatus() << endl;
  cout << seat1.getAvailability() << endl;
seat1.setStatus(StatusA);
  cout << seat1.getStatus() << endl;
  cout << seat1.getAvailability() << endl;
  Flight flight1(myDeparture, myDestination, 30);
  flight1.printFlight();
  Airline AA;
  AA.addFlight(&flight1);
  AA.addFlight(&flight1);
  AA.removeFlight(&flight1);
  AA.removeFlight(&flight1);
  cout << AA.checkAvailability(myDeparture,myDestination) << endl;
}
And the output:

San Franscisco
10
Available
1
Sold
0
Available
1
The flight from Boston to San Franscisco with 30 seats has 30 seats available.
0
0
1
Warning: Flight is already there!
Flight you're trying to remove isn't there!!!
Flight with given departure and destination does not exist!
0

Which is what I expected! . Or rather, hoped for.
SenorKeeed's adventures in C++ Quote
04-12-2013 , 07:10 PM
You keep teasing with parts of the picture. Let's see flight.h!

There is a real problem here, which we'll get to.
SenorKeeed's adventures in C++ Quote
04-12-2013 , 07:12 PM
Flight.h

Code:
#include <string>
#include "Seat.h"

using namespace std;

class Flight {
 private:
  string departure;
  string destination;
  int capacity;
  int availableSeats;
 Seat** ptrSeats;
 public:
 Flight();
  Flight(string myDeparture, string myDestination, int myCapacity);
  void setDeparture(string newDeparture);
  void setDestination(string newDestination);
  void setCapacity(int newCapacity);
  void setAvailableSeatsNumber(int newAvailableSeats);
  string getDeparture();
  string getDestination();
  int getCapacity();
  int getAvailableSeatsNumber();
  void printFlight();
};
Seat.h
Code:
#ifndef SEAT_H
#define SEAT_H

#include <string>
using namespace std;

class Seat {
 private:
  int seatNumber;
  string status;
  bool available;
  string passengerName;
 public:
  Seat(int mySeatNumber, string myStatus, bool myAvailable);
  ~Seat();
  void setSeatNumber(int seatNumber);
  void setStatus(string status);
  int getSeatNumber();
  string getStatus();
  bool getAvailability();
  void setPassengerName(string);
  string getPassengerName();
};

#endif
SenorKeeed's adventures in C++ Quote
04-12-2013 , 07:46 PM
ok, here are some basic problems.

1. What makes a flight a flight is {source, dest, capacity}. You are doing your check for dupes in addFlight by checking for the same address on a flight object. That isn't what you want.

Code:
Flight f1("SFO", "JFK", 400);
Flight f2("SFO", "JFK", 400);
if(f2 != f1)
{
launchNukes();
}
You will launch the nukes here. f2 and f1 have different addresses but contain the same data. If you want to see if two things are equal, look at the properties that make them equal.

2. You are allocating flights on the stack, then storing the address in something that was allocated on the heap. That is a recipe for trouble. You save the address but it becomes junk soon enough. Then you try to use it and crash.

I wonder why you are trying to add complete flight objects to the Airline instead of just adding source, dest, capacity.

Some evidence of where you went wrong is your public default constructor for flights. A flight to nowhere doesn't really make sense. I would make that private so you know flights are all legit.

I would also just pass the source, dest, capacity to Airline.AddFlight(). Let the airline create the flight since it will own it.
SenorKeeed's adventures in C++ Quote
04-12-2013 , 08:22 PM
Quote:
Originally Posted by Chips Ahoy
ok, here are some basic problems.

1. What makes a flight a flight is {source, dest, capacity}. You are doing your check for dupes in addFlight by checking for the same address on a flight object. That isn't what you want.

Code:
Flight f1("SFO", "JFK", 400);
Flight f2("SFO", "JFK", 400);
if(f2 != f1)
{
launchNukes();
}
You will launch the nukes here. f2 and f1 have different addresses but contain the same data. If you want to see if two things are equal, look at the properties that make them equal.
Thanks, this makes sense.

Quote:
2. You are allocating flights on the stack, then storing the address in something that was allocated on the heap. That is a recipe for trouble. You save the address but it becomes junk soon enough. Then you try to use it and crash.
So in my main function I should declare my flight objects like

Flight* f1=new Flight(dept,dest,cap);

Quote:
I wonder why you are trying to add complete flight objects to the Airline instead of just adding source, dest, capacity.
It's explicitly stated in the assignment that we do this.

Quote:
Some evidence of where you went wrong is your public default constructor for flights. A flight to nowhere doesn't really make sense. I would make that private so you know flights are all legit.
That make sense.

Quote:
I would also just pass the source, dest, capacity to Airline.AddFlight(). Let the airline create the flight since it will own it.
Probably a better way to do it, but again not allowed as per the instructions.
SenorKeeed's adventures in C++ Quote
04-12-2013 , 08:28 PM
Is there any difference between

int* p=x;
int *p=x;

My book seems to always use int *p, but people in this thread seem to put the asterisk next to the class rather than the pointer. But then sometimes my book will put a space on either side:

const double * const pValue = &radius;

I can't seem to find an explanation as to why, how, or if it matters.
SenorKeeed's adventures in C++ Quote
04-12-2013 , 09:45 PM
Both are the same. For the most part C++ does not care about whitespace.

I prefer int* p because it emphasizes pointer to int (the data type), not the variable name. p is a variable of type "pointer to int".

The const one is more tricky
const double * const p
double const * const p

are actually the same!.

I actually prefer the 2nd one (I know this probably the minority in C++ community). The type is a "constant pointer to double" (double const*), meaning you cannot modify the object through the pointer (only call const functions). The variable is also constant (const p).
SenorKeeed's adventures in C++ Quote
04-12-2013 , 09:57 PM
Quote:
Originally Posted by SenorKeeed
Is there any difference between

int* p=x;
int *p=x;
They mean the same thing. Some (most?) people prefer the int* p=x; version because it clearly delineates the type declaration and the variable name (i.e. you can read "int* p" as declaring a variable named p whose type is pointer-to-int). The problem with doing it this way is if you do multiple declarations on one line: "int* p, x, y" creates one pointer-to-int named p, and two plain ints (x and y), which is confusing, and is solved by using the other version ("int *p, x, y" makes it clear that p is a pointer, while x and y are not). The best solution to this problem is to limit pointer declarations to one per line.

Edit: I was too slow!
SenorKeeed's adventures in C++ Quote
04-13-2013 , 02:01 PM
Quote:
Originally Posted by SenorKeeed
Is there any difference between

int* p=x;
int *p=x;

My book seems to always use int *p, but people in this thread seem to put the asterisk next to the class rather than the pointer. But then sometimes my book will put a space on either side:

const double * const pValue = &radius;

I can't seem to find an explanation as to why, how, or if it matters.
One reason your book (and most books) keeps the * with p is because eventually you will try to save time and do this:

Code:
foo* p,q;
p = new foo(); // okay, p is a pointer to foo
q = new foo(); // ERROR! q is a foo object, not a pointer
But also, it's because the writer of the book was infected at a young age with a virus known as "TheCeeLanguage" which causes the brainstem of programmers to place its emphasis on expressions, rather than types. They write "int *p" and explain that "*p is what is the int" which is correct, but it's a completely different way of thinking than the idea that "p is a pointer to an int."
SenorKeeed's adventures in C++ Quote
04-13-2013 , 02:16 PM
Yes I have decided I'm never going to try and do two assignments of anything in one line until I feel like I have a really good grasp of the language.
SenorKeeed's adventures in C++ Quote
04-14-2013 , 09:20 AM
Hey guys, I finally finished that assignment. I wanted to thank everyone who helped me out. Once I straightened out all my syntax errors it was kind of fun.

And now we have to program an Android app in teams of 5. Haha I have no idea even where to start. My idea is to do a simple game where there are two geometric shapes that get bigger and smaller at different fixed rates. Like you have a circle centered at one spot on the screen and a rectangle on another. They start small then get bigger at different rates. When one of the objects hits a wall or the other shape it starts getting smaller and will get bigger again once it reaches its original size. If you tap the screen the process stops. The goal of the game is to stop the process when the shapes are taking up the largest amount of the screen space. So we might go to a screen that says "you stopped the game when the screen was 26.4% covered. It was 31% covered 11 seconds in the past and would have been 35% covered in 35 seconds". I'm thinking we could run the process for say a minute, so there could be a timer counting down in one corner.

The GUI is to be implemented in Java, the back end is to be in C++. Any thoughts or feedback are very welcome.

Last edited by SenorKeeed; 04-14-2013 at 09:35 AM.
SenorKeeed's adventures in C++ Quote
04-14-2013 , 09:49 AM
Seems a little ambitious to me FWIW but I could definitely be wrong. In software development it is common to be overly optimistic in implementing requirements. You've done a nice job here in laying out your high level requirements. How long do you have to complete this assignment?
SenorKeeed's adventures in C++ Quote
04-14-2013 , 09:53 AM
Until May 3
SenorKeeed's adventures in C++ Quote
04-14-2013 , 12:50 PM
I thought android was all java, or can you do mixed Java/C++ now?
SenorKeeed's adventures in C++ Quote
04-14-2013 , 12:55 PM
The project guidelines say to use C++ or C for certain parts of the project, so I assume so.
SenorKeeed's adventures in C++ Quote
04-19-2013 , 02:14 PM
Hey guys. Couple of general questions. Can someone explain what

#ifndef SOMETHING_H
#define SOMETHING_H

#endif

does exactly? I know it has something to do with preventing multiple declarations of something (at least that's the error I get if I don't include it in all my .h files). But I don'r really understand what it does. My books brief paragraph on it doesn't really help me that much. Like, I don't get how I would write my files without having to use it. Not that using it is a big deal, I just want to understand what it is doing.

And about namespace, like right now I just reflexively write using namespace std; on the first lines of all my cpp files without really thinking about it much. But our current homework uses a different namespace, draw. This is just a shorthand for a bunch of

#include <whatever>

header lines, right? Do I need to have an understanding of namespace any deeper than that?
SenorKeeed's adventures in C++ Quote
04-19-2013 , 03:04 PM
The #ifndef FILE_H #define FILE_H ... #endif is called an include guard. It prevents the contents of the .h file from being included by the compiler more than once. For example, let's say you have a SomeClass.h file:
Code:
class SomeClass { };
And you have AnotherClass.h, which depends on SomeClass:
Code:
#include "SomeClass.h"
class AnotherClass: public SomeClass { };
And finally, you have MainProgram.cpp, which includes both AnotherClass.h and SomeClass.h:
Code:
#include "AnotherClass.h"
#include "SomeClass.h"
int main()
{
    SomeClass someObject;
    AnotherClass anObject;
}
In this scenario, SomeClass.h will be included twice: once directly by MainProgram.cpp, and once by AnotherClass.h. This will cause a naming conflict, as SomeClass will be defined twice. So using include guards prevents this problem: The first time the compiler sees the #ifndef FILE_H, it looks for a preprocessor symbol named "FILE_H." It doesn't find that, so it goes to the next line: "#define FILE_H". This causes the preprocessor to add "FILE_H" to it's list of defined symbols. So the next time it encounters "#ifndef FILE_H", it finds that FILE_H is defined, and it skips to the #endif.

This is the standard way of preventing multiple inclusions of .h files, but I prefer to simply put "#pragma once" at the top of every .h file, which accomplishes the same thing much more simply.

As for namespaces, no, a "using namespace xxx" is not equivalent to doing a bunch of "#include xxx_1". In c++ you can declare things within a namespace, like so:
Code:
namespace sards
{
   class MyClass;
}
Now if you want to access MyClass from outside of the sards namespace, you have to use "sards::MyClass". If you don't want to type out the "sards::" part every time you use MyClass, you can say "using namespace sards;", which will allow you to use all the names in the sards namespace without the sards:: prefix.

Namespaces are used to prevent naming conflicts. If all code were in a single global namespace, there would be name conflicts in projects which use multiple libraries. All the c++ standard library is defined within the "std" namespace. So to use the standard library, you have three options: always use the "std::" prefix, use "using namespace std", or use e.g. "using std::string", which only imports "std::string" into the global namespace, and not all the stuff in namespace std.
SenorKeeed's adventures in C++ Quote
04-19-2013 , 05:09 PM
Thank you.
SenorKeeed's adventures in C++ Quote
04-22-2013 , 04:30 PM
God this class is so infuriating. "Hey, you know that programming language that you're just sort of getting familiar and comfortable with that we've been using all semester? lol jk, here, make an Android app in a different language."
SenorKeeed's adventures in C++ Quote
04-24-2013 , 12:18 PM
Hey guys,

We've decided to to a metronome app. I can think of two different approaches, either concatenating our tone with no periods of no sound and producing a long sound file with the appropriate beat spacing, or just repeatedly play the same sound with a certain delay.

Like if our sound was 150 ms and we wanted to play one BPS, it could be something like

boolean keepPlaying=true;
while (keepPlaying==true) {
//wait for 850 ms, can't find a simple way to do this
metronomeSound.start();
}

I can't seem to find out how to do this unfortunately, there doesn't seem to be a way to just pause for a set amount of time that I can find in Java. And I don't know if this approach is even an appropriate way to do this, as other parts of the app might take certain periods of time, so when the program executes it might be a beat per 1.05 seconds or something.

Having done some googling, I see that the Handler class might be the right approach, as you can have it do an action at a certain time. Would this be a better approach? Or should I focus on building a sound file with appropriate beat spacing for a given BPM input then just play that?

So far I have running an app that starts a looping sound with a button click and stops it with another button click. lol that took all morning and I'm inappropriately proud of it.
SenorKeeed's adventures in C++ Quote
04-24-2013 , 03:24 PM
There are three possible approaches. The most naive looks like the example you posted: you have a loop which constantly checks the current time, and then plays the sound when the proper amount of time has elapsed. This is a bad way to do it because it is a busy wait, which will completely consume the CPU. A better way is to use a timer (see the Timer class, but Handler might work too) which you schedule to trigger a callback at a specific time or interval, and you play the sound from that callback. The only problem with that is the timer is not guaranteed to fire the callback at exactly the time it is requested. This could still be acceptable, depending on how precise timers are on Android. To get perfect timing, you will have to abandon the timer approach and directly stream the audio data (see the AudioTrack class).
SenorKeeed's adventures in C++ Quote
04-24-2013 , 11:21 PM
I don't know how precise the timing will be in reality, but here's one way to make your program sleep

Code:
java.lang.Thread.sleep(1000)
(the input is milliseconds)
SenorKeeed's adventures in C++ Quote
04-25-2013 , 10:48 AM
Thanks guys. I was able to get something working using both of the first two approaches, but ran into unacceptable problems doing both. Timer worked sort of, but there were problems with the beat frequency, and for some reason it just flat-out stopped working after like 30-35 seconds. No error messages, the sound just stopped playing. The sleep method actually had better timing and didn't stop playing, but is I think unacceptable because the app was non-responsive during sleep periods. There needs to be a stop button, so lol you'd have to time it exactly right to stop the sound. Unacceptable.

So I guess I'm going to have to generate a new audio data for each selected beat frequency. I know this is ridiculous but I kind of want to generate unique mp3 files for 40-220 bpm in MATLAB and just use that. Not elegant to say the least, but I just don't even know where to start doing this in Java/android. Is there an easy way to repeatedly concatenate a sound with silence in Java? I'm reading through the AudioTrack class but it's pretty intimidating.
SenorKeeed's adventures in C++ Quote

      
m