Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Mr.Mojo
Sep 11, 2001

Nascita di Venere
I'm doing a problem that asks me to implement logical negation, !, without using !. My idea is to use "~x+1", but the tester says this is incorrect. What am I doing wrong?

Adbot
ADBOT LOVES YOU

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
Comedy x ? false:true option.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Mr.Mojo posted:

I'm doing a problem that asks me to implement logical negation, !, without using !. My idea is to use "~x+1", but the tester says this is incorrect. What am I doing wrong?

Do you understand the semantics of logical negation? Your proposal doesn't satisfy them for... well, for anything.

Mr.Mojo
Sep 11, 2001

Nascita di Venere

rjmccall posted:

Do you understand the semantics of logical negation? Your proposal doesn't satisfy them for... well, for anything.

Oh duh, I was doing a normal negate, not a logical negate. Back to thinking about it!

Dire Penguin
Jun 17, 2006

I'm fairly new and starting to work a lot with derived classes. I've got a main class with a virtual function that should never be called, and then several derived classes each with their own different versions of said function that should always be called instead.

But, when I go through my queue calling my function on each class, it always calls the main class's function, not the derived class. Is there something simple that I'm missing?

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
Post some code.

Dire Penguin
Jun 17, 2006

Virtual function in the main class:
code:
virtual int hit(P,P,P&, P&) {printf("failure\n");};
Actual function in a derived class:
code:
int hit(P, P, P&, P&);
Declaring a new instance of the derived class & adding it to queue, where the templated type is the main class, Shape:
code:
template <class T>
void declare(Queue<T> *q){
Derivd newball(amb, mir, trans, azi, elev, roll, diff, centr, .25);
q->add(newball);
}
Calling the function from a linked list, which calls the virtual hit function instead of the Derivd:
code:
template <class T>
Shape* hitter(P sp, P dp, Queue<T> q){
P spot, tee;
Node<T>* walk = q->getfront(); //gets the front of the queue
walk->getdata()->hit(sp, dp, spot, t);
getdata() returns a pointer to whatever data is stored in the queue, which should be the Derivd newball I stuck in there earlier with q->add. Node contains a pointer to the next Node, and to data stored, getfront() would set this to be the very first Node in the queue.

cronio
Feb 15, 2002
Drifter
Since you're storing T in your queue, and not T*, what's happening is that you're actually storing a *copy* of the object you're adding. And because the queue is actually of type Point, it's using the copy constructor to create a new Point object, not a derived one, and copy just the Point data from the derived object you're adding.

You need to store pointers inside your queue, and allocate the objects on the heap:
code:
template <class T> 
void declare(Queue<T> *q){ 
  Derivd* newball = new Derivd(amb, mir, trans, azi, elev, roll, diff, centr, .25); 
  q->add(newball); 
}
And of course don't forget to delete them when they are removed from the queue.

cronio fucked around with this message at 05:31 on Sep 29, 2008

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.

Dire Penguin posted:

Queue<T>
Is your Queue holding Shapes instead of Shape*s? If so, you're not going to see polymorphic behavior because the queue isn't holding any Deriveds. Here's an ultraquick overview:
code:
Derived d(/* whatever */);
Shape s = d; // okay, copy the Shape members of d to s
s.hit(p,p,p,p); // uses the compile-time type of s, which is Shape
Shape *sp = &d;
sp->hit(p,p,p,p); // uses the run-time type of *sp, which is Derived
Shape& sr = d;
sr.hit(p,p,p,p); // uses the run-time type of the object reference by sr, which is Derived
Long story short, the member has to be called via either a pointer or a reference if you want polymorphic behavior, and assigning a derived object to a base object will* just copy the base class's members from the derived object to the base object. A book or the C++ FAQ can give you more detail.

* depending on how the copy constructor is defined, of course

Dire Penguin
Jun 17, 2006

Awesome, that's exactly what I was doing. I went back through and changed the Queue to store T* and changed my declarations and the error goes away, as far as I can tell.

cronio
Feb 15, 2002
Drifter
Whoops, noticed I had a slight typo... I didn't mean to have Queue<T*> in there.

What you really want to do is keep the queue holding T, but instantiate it with Shape* instead of Shape:

code:
Queue<Shape*> my_queue;
This lets it work for any kind of object instead of just pointers.

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

Dire Penguin posted:

Virtual function in the main class:
code:
virtual int hit(P,P,P&, P&) {printf("failure\n");};

If you make this function a pure virtual instead, it will 100% guarantee that the base version will never be called, because it doesn't even exist:

code:
virtual int hit(P,P,P&, P&) = 0;
(You also won't even be able to create an instance of Shape, because the compiler will complain that it has pure virtual functions, which'll mean the problem with creating new Shape objects in Queue<Shape> instead of just copying the points would show up at compile time instead of at runtime. This may not be what you want if you actually do want to create a Shape object instead of a derived object at some point.)

floWenoL
Oct 23, 2002

JoeNotCharles posted:

If you make this function a pure virtual instead, it will 100% guarantee that the base version will never be called, because it doesn't even exist:

That's not true.

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

floWenoL posted:

That's not true.

It is if you consider crashing with an error to be "not calling" it.

That Turkey Story
Mar 30, 2003

JoeNotCharles posted:

It is if you consider crashing with an error to be "not calling" it.

He means that pure virtual functions can be defined and called. All that pure virtual implies is that the child should specify an implementation and makes the base type abstract, not that you can't also define the function in the base and explicitly call that implementationt. Case in point, pure virtual destructors, which in that case must be defined and are always called during destruction.

That Turkey Story fucked around with this message at 20:56 on Sep 29, 2008

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.
Huh, I didn't know that. Yet another example of why C++ is so hard to master!

Anyway, it will 100% guarantee that the base version will never be called automatically - is that better?

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.

JoeNotCharles posted:

Anyway, it will 100% guarantee that the base version will never be called automatically - is that better?
Like That said, not true in the case of destructors.

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

Dire Penguin posted:

Virtual function in the main class:
code:
virtual int hit(P,P,P&, P&) {printf("failure\n");};

Yeah, C++ is supposed to have a feature that prevents this happening, but it doesn't loving work. Have fun!

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
It isn't supposed to have any such feature. If it's been advertised to you as such, you've been misled.

edit: I mean, I'm not blaming you for thinking that; that's just not what it was designed for.

Mustach fucked around with this message at 23:39 on Sep 29, 2008

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.
Uh, I'm pretty sure it's for exactly this situation - you have an abstract base class (Shape), and you want to always call the member from a subclass and not the abstract base class.

The issue is that C++ is so fiddly that I can't give a one-line description of pure virtual methods because, surprise, there are confusing corner cases. A pure virtual destructor isn't at all related to this situation because I wasn't advising him to use a destructor, but it still makes what I said incomplete and in C++ that's dangerous because there are so many features that interact that you have to be a huge rules lawyer to understand how they work.

I mean, in any other language I'd say, "Pfft, you're being pedantic. Obviously I wasn't talking about destructors, and obviously if you actively try to make your pure virtual callable by implementing it after you declare it than you deserve what you get." But in C++ that kind of pedantry is actually necessary and admirable.

more falafel please
Feb 26, 2005

forums poster

code:
#if DEBUG
#define PURE_VIRTUAL { assert(false, "Pure virtual called"); }
#else
#define PURE_VIRTUAL =0

class foo {
   void bar() PURE_VIRTUAL;
}

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.
So... you want it to be harder to find errors in debug mode?

newsomnuke
Feb 25, 2007

That Turkey Story posted:

Case in point, pure virtual destructors, which in that case must be defined and are always called during destruction.
I've read that pure virtual destructors should always be empty, but can't think of a reason for this?

Hubis
May 18, 2003

Boy, I wish we had one of those doomsday machines...

more falafel please posted:

code:
#if DEBUG
#define PURE_VIRTUAL { assert(false, "Pure virtual called"); }
#else
#define PURE_VIRTUAL =0

class foo {
   void bar() PURE_VIRTUAL;
}

why would you do this

clayburn
Mar 6, 2007

Cammy Cam Juice
I am having an issue trying to compile using g++. I am getting the following error message:
code:
file.cpp: In constructor ‘Game::Game(std::string)’:
file.cpp:551: error: no matching function for call to ‘Player::Player()’
file.cpp:251: note: candidates are: Player::Player(std::string, int, int, int)
file.cpp:207: note:                 Player::Player(const Player&)
and here is the offending code:

code:
class Player{
	
	public:
		
		//Creates a new player with:
		//	name = n
		Player(string n, int i = DEFAULT_INTELLIGENCE, int t = DEFAULT_TIME, int m = DEFAULT_MONEY);
		
		//Changes intelligence (positively or negatively) by delta
		//If delta < 0, then intelligence decreases
		void modIntelligence(int delta);
		
		//Changes intelligence (positively or negatively) by delta
		//If delta < 0, then time decreases
		void modTime(int delta);
		
		//Changes intelligence (positively or negatively) by delta
		//If delta < 0, then money decreases
		void modMoney(int delta);
		
		//Determines if player is defeated
		//True if intelligence, time, or money are zero or less
		bool isDefeated();
		
		//Prints players statistics with the following formatting:
		//Player: <name>
		//	Intelligence: <intelligence>
		//	Time: <time>
		//	Money: <money>
		void printStats();
		
		//Returns a score object for this player
		//Score = intelligence * time * money
		Score getScore();
	
	private:
		
		//Player's Name - (e.g. John Doe)
		string name;
		
		//Player's Statistics
		int intelligence, time, money;
};

Player::Player(string n, int i, int t, int m){
	name = n;
	intelligence = i;
	time = t;
	money = m;
}

//this is line 551
Game::Game(string player_name){
	player = Player(player_name);
	events = EventList();
	dungeon = Dungeon();
}
I can tell from the error message that my call to Player::Player(player_name) doesn't seem to actually pass the string player_name, seeing as the compiler says there is no call matching Player::Player(). I come from Java, so I don't really understand the problem here. Any ideas?

Pooball
Sep 21, 2005
Warm and squishy.
I'd need to see the definition of Game to be certain but it looks like you have:

class Game {
Player player;
EventList events;
Dungeon dungeon;
};

So you can't create a Game without calling Player's constructor. To use a constructor other than Player(), use an initialisation list:

Game::Game(string player_name) : player(player_name) { }

Calling player = Player(...) inside the constructor is like doing:
Player player;
player = Player(...);
It creates an instance using the default constructor, then creates another instance using another constructor and calls the assignment operator.

clayburn
Mar 6, 2007

Cammy Cam Juice
Awesome, the initialization list fixed this, thanks!

Just to get a better understanding of this, I declare Player player int the class declaration as a member variable. Upon calling the constructor, it calls the Player::Player() constructor rather than waiting and calling the Player::Player(string) that I define?

Pooball
Sep 21, 2005
Warm and squishy.
yes

That Turkey Story
Mar 30, 2003

ultra-inquisitor posted:

I've read that pure virtual destructors should always be empty, but can't think of a reason for this?

There is no reason, they should do whatever you need them to do.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
I recall there being an idiom in C++ for "template polymorphism", but I'm probably calling it by the wrong name, since Google isn't much help. I think TTS posted it in #cobol, if that helps any.

Does anyone know what I mean?

ehnus
Apr 16, 2003

Now you're thinking with portals!

Avenging Dentist posted:

I recall there being an idiom in C++ for "template polymorphism", but I'm probably calling it by the wrong name, since Google isn't much help. I think TTS posted it in #cobol, if that helps any.

Does anyone know what I mean?

The curiously recurring template pattern?

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

Nah, but that's a fun one.

The idea was that it worked somewhat like a virtual functor, but there was some template magic in place of the virtual function call. I don't even know if I'd have any use for it, but I was thinking about it the other day and couldn't find it again.

EDIT: it looked something like this
code:
class something_cool
{
public:
    template<typename T> something_cool(const T &whatever);
private:
    // Some weird template member stuff here
};

Avenging Dentist fucked around with this message at 23:10 on Sep 30, 2008

That Turkey Story
Mar 30, 2003

I don't know if there is a special name for it, I think the common term is just vaguely "static polymorphism" which could apply to a number of different things. You do generally use the curiously recurring template pattern to do it, however.

code:
#include <cstddef>

template< typename ChildType >
struct container
{
  std::size_t size() const { return static_cast< ChildType const& >( *this ).size(); } 

  // etc.
};

struct vector
  : container< vector >
{
  std::size_t size() { return 1; }
};

template< typename ChildType >
void function_expecting_a_container( container< ChildType >& a )
{
  a.size(); // in practice you actually use it
}
You can also do some compile-time magic to make sure the child member function is overwritten.

BigRedDot
Mar 6, 2008

Also seen it called "compile-time polymorphism".

emf
Aug 1, 2002



I'm just getting started with gcc's built-in vector extensions, and I want to perform the following operation on a vector:
code:
c = 0.5*(a + b);
where a, b, and c are all vectors, but I get a compiler error saying
code:
error: can't convert value to a vector
The only way I can get it to work is by creating a vector "half" where each element is equal to 0.5, and writing the operation as:
code:
c = half*(a + b);
This is not ideal, but I'm having a lot of difficulty finding a good tutorial or documentation on how to do this correctly.

I'm kind of stuck with gcc 4.1.2 as I'm on Debian stable, but if this is "fixed" in later versions I might have reason enough to lobby for a version update.

ehnus
Apr 16, 2003

Now you're thinking with portals!
That's correct because the concept of vector immediates generally doesn't exist. You'll need to splat that value across a vector variable before you can use it

emf
Aug 1, 2002



That's poopy. :(

I wanted to use very large vectors for readability (and a few other minor reasons), and there are a minimum of 5 different constant values I need to use (depending on the vector). That's going to eat a ton of memory.

Soldat
Jan 22, 2008
my name is soldat and I get respect, your cash and your jewelery is what I expect
Intro c++ here...

I'm trying to write a code that simply copies one word in a char array over to another, using pointers. I think I'm pretty close, but when I cout << str2 in my main function, all that comes out is garbage for some reason, even though the correct output comes when I cout << str2 in my copyString function. Any hints would be nice.
code:
#include<iostream>
using namespace std;

void copyString(char * str2, const char * str1){

 const char * origin = str1;

 int size = 0;
 while(*str1 != '\0')
   {size++;
     str1++;}

 str2 = new char [size+1];

 str1 = origin;

 cout << "size= " << size << endl;

 for (int i=0;i<size;i++)
   {
     str2[i]=str1[i];
   }

 str2[size]='\0';

 cout << str2 << endl;

}

int main()
{
 char * str1 = "Hello!";
 char * str2;
 copyString(str2, str1);
 cout << "str1= " << str1 << endl;
 cout << "str2= " << str2 << endl;
 // delete [] str2;
 return 0;
}

Edit: I just changed it, but for some reason I accidentally changed str2 to str3 when I copied it over here, sorry about that

Soldat fucked around with this message at 00:28 on Oct 2, 2008

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
Ignoring the fact that your code doesn't even compile (str3 should be str2), you aren't allocating space for the destination string. You're just changing what str2 points to in copyString. All of this is secondary to the more important questions though: why aren't you just using std::string, and if you feel you absolutely MUST use char*s, why aren't you just using the functions in the C standard library, like strdup?

Furthermore, in 99% of situations (especially in C++), it's bad practice to allocate memory in a function and then expect the calling function to free that memory.

Adbot
ADBOT LOVES YOU

Soldat
Jan 22, 2008
my name is soldat and I get respect, your cash and your jewelery is what I expect
Sorry I should have clarified, I think we're only supposed to use char arrays. I can post the spec if that helps:
code:
Name:  copyString
2 Arguments:  char * and const char *, respectively, representing the destination and source strings.
   These variables may or may not be references!
Return: none
State Change:  arg2 points to an array of char containing the same characters as the array of char
   pointed to by arg1.
Also, could you clarify what you mean by saying I'm not allocating space for the destination string? I thought I was dynamically allocating space for it with the line:

str2 = new char [size+1];

EDIT: nevermind, thanks for the advice dentist. I changed where I was allocating space and tweaked a couple of other things, it works now.

Soldat fucked around with this message at 00:39 on Oct 2, 2008

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply