I try to call another constructor in one constructor, but it doesn't work.
here is the exaple:
How can I do that? Thanks!Code:class A
{
A(int a);
A(int a, int b);
}
A::A(int a)
{
....
}
A::A(int a,int b)
{
A::A(a);
....
}
Printable View
I try to call another constructor in one constructor, but it doesn't work.
here is the exaple:
How can I do that? Thanks!Code:class A
{
A(int a);
A(int a, int b);
}
A::A(int a)
{
....
}
A::A(int a,int b)
{
A::A(a);
....
}
I don't think it's possible, but you can create a function which you can call from both constructors, and in this particular case you can use default parameter.
Calling another constructor from the same class is not possible, but like RoboTact said, use a init function and call that from all your constructors.
No I don't think either that it is possible. I think calling the constructor of a class from another constructor would just construct a new instance of the class.
You either write a private "init()" function or just rewrite the member initializer list everytime.
If that's appropriate for your situation, you can also just have one constructor that takes two int arguments, with a default value for the second one.
If you do this:
I reckon it compiles and constructs a temporary object of A constructed with a and then does nothing with it.Code:A::A( int a, int b )
{
A::A(a);
}
That's what it does in Visual C++ 6.0. In fact I changed it to this:Quote:
Originally Posted by NMTop40
and when I stepped through it in the debugger, the temporary object created by the line A::A(a) had its destructor called even before the call to f(). Comeau won't compile it at all.Code:A::A( int a, int b )
{
A::A(a);
f();
}
What's your point ? Why do you want to call two contructor ?
Let me try to answer for greghua. :)
I have been seeing quite a few posts asking if it is possible to call a constructor from another constructor within the same class. Most of time, the reason given is to eliminate the duplicate code for initialization in both constructors.
Although, calling another constructor may create another object, the constructor doesn't prevent us to call another function. Thus, you can have a common init() function to be called by both constructors.
Code:
A::A(int a, int b)
{
//...
init(a);
}
A::A(int a)
{
//...
init(a);
}
A::init(int a)
{
//...
}
Dear greghua,
I agree with Mr. Kheun's approach of calling an intermediate function from all constructors. Thats the approach I mostly use --- with the occational exception of using default values.
The trick is:
The <Default Value> would be the value you would be assigning to member b, if argument b were not supplied. This is equivalent to the two function version you have posted and is quite useful when you want to expand to muti-variable initialization. (But if the variable are too many, try considering the property fields instead).Code:class A
{
A(int a, int b = <Default Value> );
};
A::A(int a, int b)
{
....
}
When you cannot decide an appropriate default value, then you can fall back to the intermediate init() function mechanism.
Ofcourse, you can combine both approaches and that would give you the mechanism for "Reset" functionality for objects.
All the best.
Thanking you,
Yours,
P.GopalaKrishna.
A::A(a) is clearly not the normal syntax to create an object but is it right that the object deletes before the end of the function?Quote:
Originally Posted by Smasher/Devourer
Suppose that our class is an automatic mutex lock. I might want to create a temporary thus:
I would normally expect aMutex to be locked until the end of the function, even if I haven't assigned this temporary to any particular named object. ThusCode:void SomeFunction()
{
AutoMutexLock( aMutex );
// do code that needs the mutex locked
}
I would expect to do exactly the same thing, except that in the latter case I can access the lock through aLock.Code:void SomeFunction
{
AutoMutexLock aLock( aMutex );
// do code
}
Maybe someone who knows the standard well can answer this question.
Life gets much simpler if you stop thinking of constructors and destructors as callable entities. The standard (12.1/1) says "Constructors do not have names." You can't call something that doesn't have a name. (And use of the class name to identify the ctor or dtor is a "special declarator syntax", not a name.) I know that destructors are callable, but this should only be done under very specialised circumstances.
I just find it easier to mentally label ctors and dtors as "things that happen at construction and destruction". This way, you don't even think about doing things that you can't.
But when you construct a temporary should its scope last as long as it would if you had assigned it to a named variable (as with my mutex-locking example)?
Under Solaris I used to create temps this way and it worked but it doesn't work properly under VC++ (even 7.1) where you have to use a named variable to store the return type.
Dito. Did you even read my post? I said that it would only create a temporary instance of the class A. :rolleyes:Quote:
Originally Posted by Smasher/Devourer
:D Very true..very true...Nice quote...Cheers :thumb:Quote:
Originally Posted by Graham
Well, I'm no standards wiz, but I am fairly certain that a temporary should only stay alive as long as the expression it's in (i.e. to the ; after it). (EDIT: Unless it's bound to a const reference) If you want an object to live longer than that, you have to name it. To me that makes sense as you wouldn't need the object to stay alive any longer, as you can't access it. (Though your lock example would be a good use for something like that.)Quote:
Originally Posted by NMTop40
I think it should (effectively) stay for entire function, but in certain cases it can be changed by compiler the way it wouldn't make difference.
I'm sorry if I misunderstood you, NoHero. I did read your post, but although you said a temporary instance of A would be created, I wasn't clear on when that temporary would be destroyed. Like NMTop40, I would have expected it to be destroyed at the end of the function, and the fact that it was destroyed earlier surprised me.Quote:
Originally Posted by NoHero
The lock example is just one example of creating an RAII object. Sometimes these objects may be a really complex template type that a user would not want to bother to type out. For example, a scoped-closer:
The template AutoCloser should call cl(t) when it is destructed, where cl is a "close" function. AutoOpen is a function that opens t by calling t = op(p). (Note you can have other AutoOpen functions with the same AutoCloser).Code:template < typename T, typename Cl >
class AutoCloser
{
private:
Cl m_cl;
T& m_t;
public:
AutoCloser( Cl cl, T t ) : m_cl( cl ), m_t( t )
{
}
~AutoCloser()
{
m_cl( t );
}
};
template < typename T, typename Op, typename Cl, typename P >
boost::shared_ptr< AutoCloser< T, Cl > > AutoOpen( T&t, Op op, Cl cl, P p)
{
t = op( p );
return new AutoCloser<T, Cl>( t, cl ); // uses implicit constructor
}
It returns a boost::shared_ptr to a class but for any user to have to specify the type, which would include the type of the function cl, gets rather complicated.
(Note, I worked around this problem by creating a class called AutoCloserBase, then you derive your AutoCloser template from it, and use a shared_ptr<AutoCloserBase> which is easy enough for any user to type out. The destructor of AutoCloserBase is virtual, of course, so your destructor does get called as appropriate).
In ur derived class constructor u can call the base class contructor as follows:
class base
{
.......
base{}
};
class der
{
........
der( a,b:base(c))
{}
};
I meant temporary because you cannot access this object. Well "temporary" was a bad word choice too.Quote:
Originally Posted by Smasher/Devourer
No you can't. There are a lot of syntactical errors in there.Quote:
Originally Posted by pranavsharma
The constructor of der may call a constructor of base in its initialiser list, if it doest not with to use the default constructor of base. If base does not have a default constructor, or if the default constructor is private, then der MUST call another constructor of base in its initialiser list.
The copy-constructor of der will invoke the copy constructor of base unless overridden (in the initialiser list) to do otherwise.
What you might have meant was:
Note that the base class is always constructed first. Thus you can't do this:Code:class base
{
public: // or protected
base( int b );
};
class der : public base // or inheritance private or protected
{
public:
der ( int a, int b ) : base( b ) // , other initialisations
{
}
};
The code above would compile but it would ignore the ordering in your initialiser list and construct base first from an uninitialised variable.Code:class der : public base // or inheritance private or protected
{
private:
int b;
public:
der ( int a ) : b( a*a), base( b )
{
}
};
The lifetime of each variable is really important and well defined by the standard.Quote:
Originally Posted by RoboTact
When a temporary object is constructed in a statement, it is destroyed just before the next statement.
When a variable is declared in a code block (any piece of code between '{' and '}' characters), it is destoyed at the end of the code block.
Moreover objects are destroyed in the reverse order they are declared in the code block.
For example:
You see that if ClassNeedingAStringAndUsingThisStringDuringAllHisLifeTime was destroyed after x (for example at the end of the function), it will probably crash, because the destructor of this class supposes that the const char* string passed in his constructor is valid.Code:void f()
{
if (something)
{
std::string x=/*...*/;
AFunction(ClassNeedingAStringAndUsingThisStringDuringAllHisLifeTime(x.c_str()));
// Some code here...
} // x destroyed
else
{
// some code here : if the condition is false, x is never constructed
}
}
A more realistic example, is the use of ostream:
Code:void AFunction()
{
MyStreamBufImplementation buf;
ostream output(&buf);
output<<"some string put in the buffer and not yet flushed";
} // at this position if buf was destroyed before output it will crash when output is destroyed, because ostream::~ostream flushes the buffer on an invalid (already destroyed) streambuf object.
The temporary lasts until the end of the expression it's created in, unless it's bound to a const reference, in which case, it has the lifetime of the reference.
Standard, 12.2/3:
And paragraphs 4 & 5:Quote:
[...]Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. [...]
(The exceptions are mostly just clarifications and don't make much difference to the argument.)Quote:
4 There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression. The first context is when an expression appears as an initializer for a declarator defining an object. In that context, the temporary that holds the result of the expression shall persist until the object’s initialization is complete. [...]
5 The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object to a subobject of which the temporary is bound persists for the lifetime of the reference except as specified below. [...]
Code:A::A(a); // Dies almost immediately
const A& r = A::A(a); // Dies when r goes out of scope
Thank-you. The first statement answers my question. Thus my first example of using AutoMutexLock won't work and you must assign a variable to it as with the second example.Quote:
When a temporary object is constructed in a statement, it is destroyed just before the next statement.
When a variable is declared in a code block (any piece of code between '{' and '}' characters), it is destoyed at the end of the code block.
And that would also explain why when using a function like AutoOpen() you have to assign the return value. (As it happens though, the shared pointer to the AutoCloseBase will work with ANY object that we wish to use simply for RAII, and AutoCloseBase is a totally empty class with nothing but an empty virtual destructor. In fact, by typedef'ing the shared pointer to it, which I have done, your programmers don't even have to know you are using boost::shared_ptr).