Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ Programming ➜ General ➜ Forcing the Explicit Constructor

Forcing the Explicit Constructor

It is now over 60 days since the last post. This thread is closed.     Refresh page


Pages: 1 2  

Posted by David Haley   USA  (3,881 posts)  Bio
Date Tue 17 Nov 2009 07:26 PM (UTC)
Message
Normally, the default constructor is always called. I'm not sure what exactly you're trying to accomplish other than that?

If you define another constructor, and not the default constructor, it will demand that you use that constructor.


$ cat test.cpp 

#include <iostream>
#include <string>

class A
{
    public:
        A(int val) { val_ = val; }
        int val_;

};

int main(int argc, char ** argv)
{
    A a1(1);
    std::cout << a1.val_ << std::endl;
    A a2;
    std::cout << a2.val_ << std::endl;
    return 0;
}

$ g++ -Wall test.cpp
test.cpp: In function 'int main(int, char**)':
test.cpp:17: error: no matching function for call to 'A::A()'
test.cpp:8: note: candidates are: A::A(int)
test.cpp:6: note:                 A::A(const A&)
$ 


Line 17 is the one that declares a2.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #1 on Tue 17 Nov 2009 07:38 PM (UTC)
Message
I'm not quite sure what you mean by Class myclass. My test program here illustrates what I think you are talking about:


#include <iostream>
using namespace std;

class myclass
{
  public:
    myclass () { cout << "constructor A called" << endl; }
};


int main (void)
{
cout << "making A" << endl;

myclass A;

cout << "making B" << endl;

myclass B ();

}



However this gives slightly surprising output:


$  g++ test1.cpp -o test && ./test

making A
constructor A called
making B


There is no message for the construction of B. I suppose A takes the default constructor, but I would have expected no message more for A rather than B, as A does not have an argument list.

As a rough guess I assume that the line "myclass B ();" is constructing a temporary object.

Or have I misunderstood the problem?

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #2 on Tue 17 Nov 2009 08:01 PM (UTC)

Amended on Tue 17 Nov 2009 08:02 PM (UTC) by David Haley

Message
myclass B ();

Ah -- you've run into a very fun and exciting syntactic quirk!

You have actually declared a function called B that returns a myclass and that takes no arguments.


$ cat test.cpp 

#include <iostream>
#include <string>

class A
{
    public:
        A() { v = 1; std::cout << "A()" << std::endl; }

        int v;
};

A a2()
{
    std:: cout << "calling a2" << std::endl;
    return A();
}

int main(int argc, char ** argv)
{
    A a1;
    A a2();

    std::cout << a1.v << ", " << a2().v << std::endl;
    return 0;
}

$ g++ test.cpp && ./a.out 
A()
calling a2
A()
1, 1
$ 


What fun :-)

EDIT: you can see this by taking out the a2() function definition: then the linker will complain at you about undefined functions.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #3 on Tue 17 Nov 2009 08:32 PM (UTC)
Message
Yes, well I tried:


myclass B ();

B ();


... thinking this might force the construction of B, and call the constructor, but you are right, it gave:


/tmp/ccdtZB7e.o: In function `main':
test1.cpp:(.text+0xc7): undefined reference to `B()'
collect2: ld returned 1 exit status


This was why I thought maybe B was a temporary object, but your explanation makes more sense.

Now I wonder what the OP is really trying to do here - perhaps he is having a similar problem.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #4 on Tue 17 Nov 2009 08:37 PM (UTC)
Message
Now, where has the question gone? I see from the forum audit trail that Terry deleted his question 13 minutes after your response, David.

Please, do not delete questions. The response doesn't make any sense without the question, and the question/response sequences are supposed to be a knowledge base that may help other people.

Part of the reason David and I (and other forum posters) answer questions in detail is that the questions and answers are supposed to be there in future to help others with similar problems, so we don't have to answer the same questions multiple times.

Deleting the question once YOU have been helped subverts that.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #5 on Tue 17 Nov 2009 08:39 PM (UTC)
Message
For the record, the original question was:

Quote:

I was wondering if it was possible to "force" an object to be constructed via the explicit constructor, rather than the default one? What I want is for something like
Class myClass; to be handled the same as Class myClass();. Either that, or make it so that member functions can see if the explicit constructor was called?

At first, I thought of doing something like bool _isConstructed; and put _isConstructed(true), in the initializer list, but then I realized there's no way of knowing it will be false originally... Is there no way of doing something like any of the ideas I've mentioned?


- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Terry   USA  (87 posts)  Bio
Date Reply #6 on Tue 17 Nov 2009 08:39 PM (UTC)

Amended on Tue 17 Nov 2009 08:53 PM (UTC) by Terry

Message
Yeah, this whole time I've been testing out stuff that you guys've been talking about, which is why I haven't responded. I'm getting a lot of errors, from this code, and I can't really understand why. :P

// dice.h
#include <cstdlib>


class Dice
{
public:
	Dice(const int unsigned numDice, const unsigned int sides);
	void rollDice();
	int getDie(const unsigned int die) const;
	int getDice() const;
	int getSum() const;
	int getPoint() const;
private:
	static const unsigned short MAX_DICE, MAX_SIZE;
	extern const unsigned short NUM_DICE, DICE_SIZE;
	unsigned int *_dice;
	unsigned long _sumOfDice;
};

// dice.cpp
#include "dice.h"


const unsigned short Dice::MAX_DICE = 100;
const unsigned short Dice::MAX_SIZE = 1000;


Dice::Dice( const unsigned int numDice = 2, const unsigned int sides = 6 )
:NUM_DICE((numDice <= MAX_DICE) ? numDice : MAX_DICE), DICE_SIZE((sides <= MAX_SIZE) ? sides : MAX_SIZE)
{
}


void Dice::rollDice()
{
	int dice[NUM_DICE], sum;
	for( unsigned short die = 0; die < NUM_DICE; ++die )
	{
		const roll = 1 + (std::rand() % DICE_SIZE);
		dice[die] = roll;
		sum += roll;
	}
	
	_dice = dice, _sumOfDice = sum;
}


int Dice::getDice() const
{
	return NUM_DICE;
}

int Dice::getDie( const unsigned short die ) const
{
	if( die >= NUM_DICE )
		return -1;

	return _dice[die];
}

int Dice::getSum() const
{
	return _sumOfDice;
}


// main.cpp
#include <cstdlib>
#include <iostream>
#include <string>
#include <sstream>

#include "dice.h"


std::string printSum(Dice *roll);


int main()
{
  std::srand(static_cast<unsigned int>(std::time(0)));

  Dice d1(1, 5);
  std::cout << "d1: " << printSum(d1) << std::endl;
  Dice d2();
  std::cout << "d2: " << printSum(d2) << std::endl;

  return EXIT_SUCCESS;
}

std::string printSum(Dice *roll)
{
  std::ostringstream oss;

  for( unsigned short i = 0; i < roll.getDice() - 1; ++i )
    oss << roll.getDie(i) << " + ";
  oss << roll.getDie(roll.getDice() - 1) << " = " << roll.getSum();

  return oss.str();
}


[brainfrz@li100-29 dice]$ g++ -o main dice.cpp main.cpp
dice.h:15: error: storage class specified for âNUM_DICEâ
dice.h:15: error: storage class specified for âDICE_SIZEâ
dice.cpp: In member function âvoid Dice::rollDice()â:
dice.cpp:19: error: ISO C++ forbids declaration of ârollâ with no type
dice.cpp:24: error: invalid conversion from âint*â to âunsigned int*â
dice.cpp: At global scope:
dice.cpp:33: error: prototype for âint Dice::getDie(short unsigned int) constâ does not match any in class âDiceâ
dice.h:9: error: candidate is: int Dice::getDie(unsigned int) const
dice.h:15: error: storage class specified for âNUM_DICEâ
dice.h:15: error: storage class specified for âDICE_SIZEâ
main.cpp: In function âint main()â:
main.cpp:17: error: cannot convert âDiceâ to âDice*â for argument â1â to âstd::string printSum(Dice*)â
main.cpp:19: error: cannot convert âDice (*)()â to âDice*â for argument â1â to âstd::string printSum(Dice*)â
main.cpp: In function âstd::string printSum(Dice*)â:
main.cpp:28: error: request for member âgetDiceâ in ârollâ, which is of non-class type âDice*â
main.cpp:29: error: request for member âgetDieâ in ârollâ, which is of non-class type âDice*â
main.cpp:30: error: request for member âgetDieâ in ârollâ, which is of non-class type âDice*â
main.cpp:30: error: request for member âgetDiceâ in ârollâ, which is of non-class type âDice*â
main.cpp:30: error: request for member âgetSumâ in ârollâ, which is of non-class type âDice*â
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #7 on Tue 17 Nov 2009 08:40 PM (UTC)

Amended on Tue 17 Nov 2009 08:41 PM (UTC) by Nick Gammon

Message
There is no [code=<something>] tag, just use [code]

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Terry   USA  (87 posts)  Bio
Date Reply #8 on Tue 17 Nov 2009 08:43 PM (UTC)
Message
Oh geez. Wow. I didn't realize I deleted the question. :| I thought that I'd accidentally reposted the question, because it was at the bottom... I'm not quite sure how that happened... =\ Apologies.
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #9 on Tue 17 Nov 2009 08:44 PM (UTC)
Message

#include "dice.h"


const unsigned short Dice::MAX_DICE = 100;
const unsigned short Dice::MAX_SIZE = 1000;



Inside dice.h it needs to know MAX_DICE, but you define it too late. You need to rework this.

Terry said:

Oh geez. Wow. I didn't realize I deleted the question. :| I thought that I'd accidentally reposted the question, because it was at the bottom... I'm not quite sure how that happened.


When you reply, it puts the posts in reverse order, so the one you are replying to is near the top.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #10 on Tue 17 Nov 2009 08:47 PM (UTC)
Message
I withdraw my comment about needing to define it first, but this looks strange:


extern const unsigned short NUM_DICE, DICE_SIZE;


What are you trying to do exactly?

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #11 on Tue 17 Nov 2009 08:52 PM (UTC)
Message
Also, this is wrong:
const roll = 1 + (std::rand() % DICE_SIZE);

you need a type here, like 'int' or something.
Your probability math is not strictly correct either, but it's close enough for government work I suppose.

(You're assuming that each number has an equal number of occurrences in the range 0 .. std::rand(). But if std::rand() -- which stops at RAND_MAX, IIRC -- doesn't land evenly on a multiple of DICE_SIZE, some numbers will be slightly less probable. But if RAND_MAX is sufficiently large, you won't really notice this.)

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Terry   USA  (87 posts)  Bio
Date Reply #12 on Tue 17 Nov 2009 09:00 PM (UTC)
Message
Nick Gammon said:

I withdraw my comment about needing to define it first, but this looks strange:


extern const unsigned short NUM_DICE, DICE_SIZE;


What are you trying to do exactly?

I want the number and size of dice to be set by the constructor, which is why I wanted to require the constructor in the first place. :B I made a default parameter for both, thinking that it would make Dice d1(2, 6); behave like Dice d1();, but apparently that isn't the case. =\
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #13 on Tue 17 Nov 2009 09:51 PM (UTC)
Message
Why do this?


Dice(const int unsigned numDice, const unsigned int sides);

...

private:
	static const unsigned short MAX_DICE, MAX_SIZE;
	extern const unsigned short NUM_DICE, DICE_SIZE;


You are storing shorts (16 bits) but getting an int (32 bit) as the argument. You are just asking for compiler warnings here.

Anyway, let me see if I can make this work a bit better ...

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #14 on Tue 17 Nov 2009 10:18 PM (UTC)
Message
Hmmm - I don't really want to post a completely revised version as I suspect this is some sort of homework or something, and even if not, you wouldn't learn anything if someone else does all the work.

Basically you need to carefully revise everything you have done.


  • For example, this doesn't make any sense:

    
    Dice::Dice( const unsigned int numDice = 2, const unsigned int sides = 6 )
    :NUM_DICE((numDice <= MAX_DICE) ? numDice : MAX_DICE), DICE_SIZE((sides <= MAX_SIZE) ? sides : MAX_SIZE)
    


    You have declared NUM_DICE and DICE_SIZE as:

    
    extern const unsigned short NUM_DICE, DICE_SIZE;
    


    Since these are member variables for this particular instance of the object that should not be extern.

  • Then I would make up your mind what your data type is going to be. So far you have used unsigned int, int, unsigned short and long. Choose a type and stick to it (eg. short).

  • You have declared a pointer:

    
    unsigned int *_dice;
    


    This means you need to allocate memory for it (eg. with new or malloc). This line won't do it:

    
    _dice = dice
    


    That is just assigning a local variable in rollDice to the pointer. Even if the compiler accepts this, it will crash because the memory will go out of scope as soon as the function returns.

  • This line is inconsistent:

    
    Dice(const int unsigned numDice, const unsigned int sides);
    


    One is "int unsigned" and the other is "unsigned int". Even if they are semantically the same (David would know), be consistent.

  • You have in your class declaration:

    
    int getDie(const unsigned int die) const;
    


    But the implementation is:

    
    int Dice::getDie( const unsigned short die ) const
    


    Again, a confusion between int and short. This will make the compiler complain.

  • You create a dice like this:

    
    Dice d1(1, 5);
      std::cout << "d1: " << printSum(d1) << std::endl;
    


    This is passing down a copy of d1 by value, but the function printSum expects a pointer:

    
    std::string printSum(Dice *roll)
    


  • I am a little surprised the compiler let you get away with this (maybe it didn't):

    
    int dice[NUM_DICE];
    


    You can't dimension an array with a variable. This is what dynamic memory allocation is all about.



I suggest starting again. Check your understanding of pointers and arrays. Be consistent in data types. If a function is declared to take a pointer, make sure you pass a pointer to it. I would steer clear of the stuff about "extern" for the maxima. A simple declaration like this would suffice for now:


#define MAX_DICE 100
#define MAX_SIZE 1000


Make the raw methods and check the compiler accepts the declarations before putting code in them.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


54,107 views.

This is page 1, subject is 2 pages long: 1 2  [Next page]

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.