Solved

Recycle Constructors ... ?

Posted on 2001-08-26
18
499 Views
Last Modified: 2012-06-21
Recycle Constructors ... ?


Is it possible to use a constructor in another constructor of the same class (in Java it is) ?

I tried the following but the compiler complains: 'Test' is not an unambiguous base class of 'Test'

I don't linke to rewrite the init stuff several times ...

    class Test {
        int i; char c;
      public:
        Test(int _i) { i = _i; /* init stuff */ }
        Test(int _i, char _c) : Test(_i) { c = _c; } // WRONG !!
    };




Is it possible to use an inherited constructor without overwriting it ?

    class A {
        string text;
      public:
        A(string _text) text(_text) { /* init stuff */ }
    };
   
    class B : public A {
      public
        print() { std::cout << text}
    };
   
    /* ... */
   
    B obj = B("Hello World");
    B.print();
   



 - Many thanks for all the other answers I got so far ...

             Ingo





.
0
Comment
Question by:bormuth
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 6
  • 5
  • +1
18 Comments
 
LVL 22

Accepted Solution

by:
nietod earned 50 total points
ID: 6427229
>> Is it possible to use a constructor in
>> another constructor of the same class
In a word--"no".

In C++ you cannot dirrectly call a constructor for a class.  The constructor may only be called by the compiler, as part of object creation.  There are ways to cause the constructor to be called, but there is no way to call it directly.  

>> I don't linke to rewrite the init
>> stuff several times ...
Often you can get away with writting a non-constructor, initialization procedure and then call this procedure from multiple constructors.  However this may be less efficient than performing the initialization directly in the constructor.  More importantly, it usually will not work to initialize members that must be constructed using a non-default constructor or to initialize constant, non-static members.

continues
0
 
LVL 22

Expert Comment

by:nietod
ID: 6427238
>> Is it possible to use an inherited
>> constructor without overwriting it ?
Constructors are never inherited.  So in your example, B does not have a constructor that takes a string parameter, so the line

 B obj = B("Hello World");

will cause a compiler error.

But you can make a derived class's constructor initialize the base class by explicitly using one of the the base class's constructors.  For example

class B : public A {
public:
    B(string _text) : // Note you forgot this colon in your sample.
      A(_text) // Invoke the base class constructor.
      {
        /* init stuff */
      }
   print() { std::cout << text}
};
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6427271
In the ctor for the derived class, just add a ctor that initializes the base class:

   <derived>(<args> : <base>( <args> ) {};

class A
{
public:
    A()            { m_s[0]=0; }    
    A( LPCSTR sz ) { strcpy(m_s, sz); }    
    char m_s[100];
};
class B : public A
{
public:
    B( LPCSTR sz ) : A( sz ) {};  // <<<< here
    B( int n ) { sprintf(m_s,"%d",n); }    
};


   A a("hi there");
   B b("hi there");
   B b2(123);
   cout << b.m_s;  // "hi there"
   cout << b2.m_s; // "123"

-- Dan
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 49

Expert Comment

by:DanRollins
ID: 6427278
Dang, I'm just not quick enough with the Answer button.

-- Dan
0
 
LVL 22

Expert Comment

by:nietod
ID: 6427291
But why on earth would you take an example that uses safe techniques, like string objects and stream objects and replace them with flawed techniques, like NUL terminated character arrays and C streams?  You don't want to suggest that those changes should be made, right!?
0
 

Author Comment

by:bormuth
ID: 6427823


1)

So, when I have const members ther is no way that prevents me from writing multible constructions ?

2)

The thing is I want to built a complex, abstract template class A with multible constructers.

The user has do derive his class from A and only add one virtual function to make it not abstract. In this user-function he can use const members of A. I don't want to make him redeclare all the constructors (this would be a bit complicated).

Is there realy no way to prevent this ?

0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6428085
>>But why on earth would you take an example...and replace ...
 
Don't flatter yourself... I did not copy your example (check the timing of the posts--I did not even see it)  My clearly-written example illustrates the basic concept using simple, easily-recognized code.  Some error-checking was omitted for clarity.  Sheesh.

-- Dan
0
 
LVL 22

Expert Comment

by:nietod
ID: 6428123
>> So, when I have const members ther is no
>> way that prevents me from writing multible
>> constructions ?
No you cna have multiple constructors.  You can't have those constructors call a single shared initialization procedure.  (Actually they can, but that procedure can't initialize the constant members.  The constant members must be initialized in the initialization section of each constructor.

>> I don't want to make him redeclare all
>> the constructors (this would be a bit
>> complicated).
constructors are never inherited.  A derived class must declare any constructors it needs.  If the derived class wants constructors that exactly mirror the base class constructors, it needs to define them.  Or the derived class can have unque constructors if it wants.  it may define only one constructor that mirrors a base class constructor it it might define constructors that don't mirror the base class ones at all.  

(This of course does not apply to the automatically generated constructors, the copy constructor and default constructor.  You don't have to define these, if you don't want, and they will be defined for you, if possible, but still they are not inherited.)

>> I did not copy your example
But he sample provided in the question uses string objects and C++ I/O.  You altered this to use dangerious techniques.  You could inadvertadtly convince a client to remove these tecyhniques in favour of poor techniques.

>> Some error-checking was omitted for clarity.
Error checking?  Its impossible to check for errors with printf()!  And error checking is practically useless with NUL-terminated character arrays.  usually the best you can do is to print out some sort of error message and kill the program.  Its better to write code that works reliably instead.  That is what the orignal program did.
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6428134
> So, when I have const members ther is no way that
> prevents me from writing multible constructions ?

You are correct...unless they can be static, (which for constants they often can be).


> In this user-function he can use const members of A.
> I don't want to make him redeclare all the constructors

In the derived class why should he have to?  He only needs to call the constructors of A that he needs.

Sometimes, const data members are more trouble than they are worth (in complex situations) - it is often better to leave them non physically const, but private and allow access via const methods - which is probably a more general way of doing it anyway.
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6428151
> My clearly-written example illustrates the basic concept > using simple, easily-recognized code.

just using gratuitously bad code...

I suppose that we must accept your view point, however, since you clearly must be writing your comments using punched cards or perhaps some sort of teletype.  Innovation and progress in computer science are clearly things which hold no value for you... ;-)
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6428160
>>?  Its impossible to check for errors with printf()!  
Describe *any* way that this could fail:

  char m_s[100];
  B( int n ) { sprintf(m_s,"%d",n); }  


>> ... That is what the orignal program did.  
You still insist that I copied your code. lol.  Your example does not even compile!  Something about string and std::

-- Dan
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6428165
> Describe *any* way that this could fail:

it is not robust under changes - array bounds come into play - and of course it is very wasteful of memory (100 bytes is excessive).

And, I see you conveniently didn't ask the same question of your base class constructor...
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6428198
>>see you conveniently didn't ask the same question of your base class constructor...
 
Didn't need to.  Addition of simple, but unnecessarily obfuscating error checking eliminates the problem:

   A( LPCSTR sz ) { strncpy(m_s, sz, sizeof(m_s) ); }    

-- Dan
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6428260
But how can it be as simple as:

std::string m_s;

A(const std::string& s) : m_s(s) {}
   
This is all rather pointless, however, since you seem to be happy using C++ as a kind of C with extra stuff.  However, perhaps you could consider this (I may have mentioned this before) - imagine writing this program (one of the simplest possible) - equivalently - in C:

#include <iostream>
#include <string>

int main()
{
   using namespace std;

   cout << "Please enter your first name\n";
   string name;
   cin >> name;
   cout << "Hello " << name << "\n";
}

Look for the answer in this article by Bjarne Stroustrup about learning C++: http://www.research.att.com/~bs/new_learning.pdf

You might learn something...but somehow I don't think it will matter to you...
0
 
LVL 22

Expert Comment

by:nietod
ID: 6428323
>> Sometimes, const data members are more trouble
>> than they are worth (in complex situations) - it
>> is often better to leave them non physically const,
>> but private and allow access via const methods -
>> which is probably a more general way of doing it
>> anyway.
And they are also often used incorrectly.  They are often used for values that are supposed to be constant for an entire class (all objects in a class, not for 1 object of a class.)  So what is often required is a static or constant static member, not a non-static constant member.  

>> Describe *any* way that this could fail:
Have you ever had a bug in one of your programs.  If not, then what you've written is fine.  If you ever make mistakes, then this code is a good opportunity for you to make mistakes that the compiler will not catch for you.  I'm not perfect, so I don't take chances.  

>> and of course it is very wasteful of
>> memory (100 bytes is excessive).
And for all that waste it is inadqeuite.  What if you need a string of 200 characters?  What about 300?  10,000?  And it is inneficient.  if the objects must be copied all that string data must be copied too.

>> Addition of simple, but unnecessarily
>> obfuscating error checking eliminates
>> the problem:
It doesn't iliminate any errors.  At best it might prevent a crash and cause unpredictable behavior instead that will be hard to track down.  What if you try to pass a string that is longer than 100 charcters?  Well you will loose information.  This goes on quitely.  The program ceases to run correctly, but there is never a clear indication of this.  That is aserious problem.  Why invite such a problem when you don't have to?

More importantly.  you don't seem to understand how strncpy works.  That is the wrong way to use it.  That code will potentially leave the string unterminated.  That as an opporunity for a different crash.  ie. you replaced one crash with a different one.  

If NUL termianted character arrays are so easy to work with, why did you make this mistake?  Maybe you aren't perfect either.  You could write code that allows the compiler to make up for your imperfections...
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6431033
You are both correct.  printf and sprintf and StrNCpy are unsafe and just possibly, the downfall of civilization as we know it. sprintf(m_s,"%d",n) fails inside the Event Horizon of massive black holes. cin >> name is a useful technique for getting input of a person's name.  Bjarne Stroustrup walks and talks with God.  

The discussion of char arrays and their initialization and the use of printf is entirely irrelevant to this question. To avoid further discord, I would like to amend my example:

class A {
public:
   A()        { m_n= 0; }    
   A( int n ) { m_n= n; }    
   int m_n;
};
class B : public A {
public:
   B( int n ) : A( n ) {};  // <<<< here
};

-- Dan
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6431299
> Bjarne Stroustrup walks and talks with God.  

I don't believe I have met anybody so unwilling to consider an argument.  I just thought, that since you clearly give no weight to either my or nietod's credentials as C++ programmers, then maybe just maybe somebody a little more well known would maybe sow a seed or two of doubt in your mind.  It seems, however, that not even Bjarne Stroustrup matches your standard.
0
 
LVL 22

Expert Comment

by:nietod
ID: 6431584
>>  printf and sprintf and StrNCpy are unsaf
You've demonstrated how they can be used incorrectly.

Your code will cause terrible problems when passed a string  that is longer than 99 characters.  Even in a short simple example like this where you try to demonstrate how to use them safely you make mistakes in which they are unsafe to use.  
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

756 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question