views:

2836

answers:

6

Hi

I know we can explicitly call the constructor of a class in C++ using scope resolution operator i.e. className::className()

I was wondering where exactly would I need to make such a call.

cheers

A: 

I don't think you would typically use that for the constructor, at least not in the way you're describing. You would, however, need it if you have two classes in different namespaces. For example, to specify the difference between these two made-up classes, Xml::Element and Chemistry::Element.

Usually, the name of the class is used with the scope resolution operator to call a function on an inherited class's parent. So, if you have a class Dog that inherits from Animal, and both of those classes define the function Eat() differently, there might be a case when you want to use the Animal version of eat on a Dog object called "someDog". My C++ syntax is a little rusty, but I think in that case you would say someDog.Animal::Eat().

Jonathan Schuster
+3  A: 

Most often, in a child class constructor that require some parameters :

class BaseClass
{
public:
    BaseClass( const std::string& name ) : m_name( name ) { }

    const std::string& getName() const { return m_name; }

private:

    const std::string m_name;

//...

};


class DerivedClass : public BaseClass
{
public:

    DerivedClass( const std::string& name ) : BaseClass( name ) { }

// ...
};

class TestClass : 
{
public:
    TestClass( int testValue ); //...
};

class UniqueTestClass 
     : public BaseClass
     , public TestClass
{
public:
    UniqueTestClass() 
       : BaseClass( "UniqueTest" ) 
       , TestClass( 42 )
    { }

// ...
};

... for example.

Other than that, I don't see the utility. I only did call the constructor in other code when I was too young to know what I was really doing...

Klaim
C++ does implicitly call the constructor of parent classes when an instance of a derived class is constructed, but it calls the default constructor - unless you explicitly call a specific the parent class constructor yourself in the initializer list.
sean riley
Yes, in my example I made sure the only valid constructor for BaseClass required some parameters. I don't remember a case really requiring explicit default constructor call. Maybe in virtual inheritance?
Klaim
+14  A: 

You also sometimes explicitly use a constructor to build a temporary. For example, if you have some class with a constructor:

class Foo
{
    Foo(char* c, int i);
};

and a function

void Bar(Foo foo);

but you don't have a Foo around, you could do

Bar(Foo("hello", 5));

This is like a cast. Indeed, if you have a constructor that takes only one parameter, the C++ compiler will use that constructor to perform implicit casts.

It is not legal to call a constructor on an already-existing object. That is, you cannot do

Foo foo;
foo.Foo();  // compile error!

no matter what you do. But you can invoke a constructor without allocating memory - that's what placement new is for.

char buffer[sizeof(Foo)];      // a bit of memory
Foo* foo = new(buffer) Foo();  // construct a Foo inside buffer

You give new some memory, and it constructs the object in that spot instead of allocating new memory. This usage is considered evil, and is rare in most types of code, but common in embedded and data structure code.

For example, std::vector::push_back uses this technique to invoke the copy constructor. That way, it only needs to do one copy, instead of creating an empty object and using the assignment operator.

Charlie Tangora
+1 for placement new. It's weird, but can be useful if you know what you're doing.
Graeme Perrow
"Indeed, if you have a constructor that takes only one parameter, the C++ compiler will use that constructor to perform implicit casts." - which is why a lot of people put the explicit keyword on single-arg constructors by default, and only take it off if they're sure they want implict casting from the parameter type to the class type.
Steve Jessop
+1  A: 

I think the error message for compiler error C2585 gives the best reason why you would need to actually use the scope-resolution operator on the constructor, and it does in with Charlie's answer:

Converting from a class or structure type based on multiple inheritance. If the type inherits the same base class more than once, the conversion function or operator must use scope resolution (::) to specify which of the inherited classes to use in the conversion.

So imagine you have BaseClass, and BaseClassA and BaseClassB both inherit BaseClass, and then DerivedClass inherits both BaseClassA and BaseClassB.

If you are doing a conversion or operator overload to convert DerivedClass to a BaseClassA or BaseClassB, you will need to identify which constructor (I'm thinking something like a copy constructor, IIRC) to use in the conversion.

Alan McBee
+1  A: 

In general you do not call the constructor directly. The new operator calls it for you or a subclass calls the parent class' constructors. In C++, the base class is guarenteed to be fully constructed before the derived class' constructor starts.

The only time you would call a constructor directly is in the extremely rare case where you are managing memory without using new. And even then, you shouldn't do it. Instead you should use the placement form of operator new.

jmucchiello
A: 

There are valid use cases where you want to expose a classes constructors. If you wish to do your own memory management with an arena allocator for example, you'll need a two phase construction consisting of allocation and object initialization.

The approach I take is similar to that of many other languages. I simply put my construction code in well known public methods (Construct(), init(), something like that) and call them directly when needed.

You can create overloads of these methods that match your constructors; your regular constructors just call into them. Put big comments in the code to warn others that you are doing this so they don't add important construction code in the wrong place.

Remember that there is only one destructor method no matter which construction overload was used, so make your destructors robust to uninitialized members.

I recommend against trying to write initializers that can re-initialize. It's hard to tell the case where you are looking at an object that just has garbage in it because of uninitialized memory vs. actually holding real data.

The most difficult issue comes with classes that have virtual methods. In this case the compiler normally plugs in the vtable function table pointer as a hidden field at the start of the class. You can manually initialize this pointer, but you are basically depending on compiler specific behavior and it's likely to get your colleagues looking at you funny.

Placement new is broken in many respects; in the construction/destruction of arrays is one case so I tend not to use it.

jls