Solved

C++ inheritance with pointers to array

Posted on 2013-02-04
19
381 Views
Last Modified: 2013-02-05
I have a main class and there are going to be many sub classes of it.  In each sub class, I would know certain fixed arrays that would provide a means for making certain calculations.  The answer is provide to the main function's array.  I could go by not doing sub classes, but only declaring instances of the parent class based on many sets of array values but I want to go more in the object oriented way.  

Below, I have made a much simpler scenario of the actual problem but I get compilation errors.  I need to understand how to resolve it and why it is happening.

Thank you.

#include<iostream>
#include<string>

using namespace std;

const int  num = 10;

const string vals[num] = {"first", "second", "third", "fourth", "Fifth", "6th", "7th", "8th", "9th", "10th"};

class A
{
public:
	A(string* s1, string* s2)
	{
		v1 = s1;
		v2 = s2;
	}
	void copy()
	{
		for(int i=0; i < num; i++)
		{
			v2[i] = v1[1];
		}
	}
protected:
	string* v1;
	string* v2;
};

class B : public A
{
public:
	B(string* s)
	{
		A(vals, s);
	}
};


int main()
{
	string ans[10];
	B b(ans);
	b.copy();
	for(int i=0; i < num; i++)
	{
		cout << ans[i] << endl;
	}
	cin.get();

	return 0;
}

Open in new window

0
Comment
Question by:farzanj
  • 10
  • 4
  • 3
  • +1
19 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 38851840
One problem is the way you are calling A's constructor from B's constructor, that should be like

class B : public A
{
public:
	B(string* s) : A(vals, s) // call base class constructor from initializer list
	{
		
	}
};

Open in new window


Then 'const' is a problem for that call - just make the array not const to avoid that, e.g.

#include<iostream>
#include<string>

using namespace std;

const int  num = 10;

string vals[num] = {"first", "second", "third", "fourth", "Fifth", "6th", "7th", "8th", "9th", "10th"};

class A
{
public:
	A(string* s1, string* s2)
	{
		v1 = s1;
		v2 = s2;
	}
	void copy()
	{
		for(int i=0; i < num; i++)
		{
			v2[i] = v1[1];
		}
	}
protected:
	string* v1;
	string* v2;
};

class B : public A
{
public:
	B(string* s) : A(vals, s) // call base class constructor from initializer list
	{
		
	}
};


int main()
{
	string ans[10];
	B b(ans);
	b.copy();
	for(int i=0; i < num; i++)
	{
		cout << ans[i] << endl;
	}
	cin.get();

	return 0;
}
                                  

Open in new window

0
 
LVL 31

Author Comment

by:farzanj
ID: 38852013
Suppose I needed to declare it a constant, what would I do?
Suppose I needed to call the super class' constructor within the function (as I recall, I used to do it) what would I do?  A::A()?

Slightly making the above example more realistic.

#include<iostream>
#include<string>

using namespace std;

const int  num = 10;

string vals[num] = {"first", "second", "third", "fourth", "Fifth", "6th", "7th", "8th", "9th", "10th"};

class A
{
public:
	A(string* s1, string* s2, const int& n)
	{
		v1 = s1;
		v2 = s2;
	}
	void copy()
	{
		for(int i=0; i < n; i++)
		{
			v2[i] = v1[i];
		}
	}
protected:
	int&    n;
	string* v1;
	string* v2;
};

class B : public A
{
public:
	B(string* s, int& n) : A(vals, s, n) // call base class constructor from initializer list
	{
		
	}
};


int main()
{
	string ans[10];
	B b(ans, num);
	b.copy();
	for(int i=0; i < num; i++)
	{
		cout << ans[i] << endl;
	}
	cin.get();

	return 0;
}

Open in new window

0
 
LVL 31

Author Comment

by:farzanj
ID: 38852039
Also, suppose I want to declare
const string vals[num] = {"first", "second", "third", "fourth", "Fifth", "6th", "7th", "8th", "9th", "10th"};

Open in new window

as

const char*  vals[num] = {"first", "second", "third", "fourth", "Fifth", "6th", "7th", "8th", "9th", "10th"};

Open in new window


With no more changes, how would I do it?
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
LVL 86

Expert Comment

by:jkr
ID: 38852220
OK, step by step - if you have references as class members, they need to be initialized in the initializer list as well:

#include<iostream>
#include<string>

using namespace std;

const int  num = 10;

string vals[num] = {"first", "second", "third", "fourth", "Fifth", "6th", "7th", "8th", "9th", "10th"};

class A
{
public:
	A(string* s1, string* s2, const int& n1) : n(n1)
	{
		v1 = s1;
		v2 = s2;
	}
	void copy()
	{
		for(int i=0; i < n; i++)
		{
			v2[i] = v1[i];
		}
	}
protected:
	const int&    n;
	string* v1;
	string* v2;
};

class B : public A
{
public:
	B(string* s, int& n) : A(vals, s, n) // call base class constructor from initializer list
	{
		
	}
};


int main()
{
	string ans[10];
        int n1 = num;
	B b(ans, n1);
	b.copy();
	for(int i=0; i < num; i++)
	{
		cout << ans[i] << endl;
	}
	cin.get();

	return 0;
}
                                            

Open in new window

0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 166 total points
ID: 38852229
OK, using a 'const char* []' does not seem to be that simple in terms of conversions - is there a reason why you would need that, especially when the classes are declared to use a 'std::string'??
0
 
LVL 31

Author Comment

by:farzanj
ID: 38852324
What is the difference between

      A(string* s1, string* s2, const int& n1)// : n(n1)
      {
            n  = n1;
            v1 = s1;
            v2 = s2;
      }

Compile time vs. run time?  So why the first one works and the other one doesn't?
0
 
LVL 31

Author Comment

by:farzanj
ID: 38852346
For all the questions that I am asking, I am trying to regain my c++ skills that I used to have in last 90's.

const char* vs. const string.

I have an impression that declaring global const strings is not a preferred practice and it is better to do const char*.  But if it is a fine practice, still I would like to know for my knowledge.

Also, how would you compile the code if
string vals[num]

was const?

const string val[num]

Can I use const_cast<> or any other mechanism?
0
 
LVL 31

Author Comment

by:farzanj
ID: 38852353
Again I could be wrong but I remember in 90's calling super class' constructor by doing something like

A::A()

But I get an error message when I try to do it.  So, is there any notation similar to it?
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 166 total points
ID: 38852420
Well, the reason is that 'n' is an 'int&' class member, and references *have* to be initialized in the initializer listbecause of their sheer nature. You could do what you described with a pointer, yet not with a reference.

Regarding the string array vs. 'char*' array issue, the compiler can easily convers a single 'char*' to a string on the fly, even with more than one argument - yet it cannot construct a string array on the fly, that you'd have to do manually. And in that case, you could as well just stick with a string array or consequently use 'char*' in the 1st place.
0
 
LVL 33

Assisted Solution

by:sarabande
sarabande earned 83 total points
ID: 38854132
all of your issues arise cause you used string pointers, global variables and c arrays.

you should use string references inted of pointers which easily can made const and can take const char * for initializing. you should use std::vector<std::string> for string arrays and you you should use static members instead of global variables.

applying all this to your classes you get

#include<iostream>
#include<string>
#include<vector>
#include <algorithm>
using namespace std;

enum
{
   first = 0, second, third, fourth, fifth, sixth, seventh, eighth, nineth, tenth, max_num 
};


class A
{
    static const char * vals[max_num];
public:
    A()
    {
    }
    void copy(std::vector<std::string>& s2)
    {
        std::copy(&vals[0], &vals[max_num], s2.begin());
    }
protected:
};

const char * A::vals[max_num] = {"first", "second", "third", "fourth", "Fifth", "6th", "7th", "8th", "9th", "10th", };

class B : public A
{
public:
    // no constructor needed
};


int main()
{
    std::vector<std::string> ans(10);
    B b;
    b.copy(ans);
    for(int i=0; i < num; i++)
    {
        cout << ans[i] << endl;
    }
    cin.get();

    return 0;
}

Open in new window


Sara
0
 
LVL 22

Accepted Solution

by:
ambience earned 251 total points
ID: 38854457
>> Suppose I needed to call the super class' constructor within the function (as I recall, I used to do it) what would I do?  A::A()?
>> But I get an error message when I try to do it.  So, is there any notation similar to it?

This.  

class A
{
protected:
      A(){}

public:
      A(string* s1, string* s2)
...
};

class B : public A
{
public:
      B(string* s, const int& n)
      {
            A(s, vals);
                A::A(s,vals);
            this->A::A(s, (string*) vals);
      }
};

The problem you had was that there wasnt any default constructor in A.

>> Also, suppose I want to declare
const char*  vals[num] = {"first", "second", "third", "fourth", "Fifth", "6th", "7th", "8th", "9th", "10th"};
           
I dont understand what you mean by "With no more changes"  

string* is not implicitly convertible to char** so without "more changes" its impossible!
                             
Also, from what I can understand, A's purpose is to copy arrays of objects. If you add const then you totally change the purpose of A.

>> I have an impression that declaring global const strings is not a preferred practice and it is better to do const char*.  But if it is a fine practice, still I would like to know for my knowledge.

The answer is - it depends.

Almost all std::string implementations implement copy-on-write and short-string-optimizations and that means if you have a lot of code copying strings from the global array its going to be pretty fast - not to mention references that are as fast as pointers. using a char* as global would require strlen whenever you need to find the length. With string you just use the size(). Additionally, std::string is more type-safe and leads to type safe code.

The downsides.

For one, it would take more space because of the internal data. It would also require some heap allocations (depending on the implementation). BUT probably the biggest gotcha is that constructors for global objects are not executed in a deterministic order - so if some other global object constructor use the global array of string, it may get uninitialized version of it. There is a simple workaround for that

const string* gArrayOfString() {
      static string array[] ...........; return array;
}

Using gArrayOfString() would ensure the array is always constructed no matter where its used - even in global object constructors. However, this looses the safety of array bounds and you'd need to find out the length of the array somehow. The best bet is to use a global vector of string

const vector<string>& gArrayOfString() ...

>> Also, how would you compile the code if
string vals[num] was const?

const string val[num]
B b(const_cast<string*>(vals), num);

not a good practice!
0
 
LVL 31

Author Comment

by:farzanj
ID: 38854722
All, thank you for your input.  As I said earlier, it is a much too simplified version I made just to ask a question that would be answered.  If I post my whole long solution, no one would be able to read the whole thing.

Sara: I used C arrays (they were considered c++ until late 90's when I used to do it) because I am writing a fast execution parser that processes TBs of data every day. So I want to use stacks instead of heap.  I didn't want global variables as I originally posted.  It was constant globals and with constants globals were considered fine, I don't know about now.  However, I can make them static member.  Class 'A' is my general parser, class 'B' would initialize tokens in class A and also over ride the pure virtual functions in class A.  So, I believe, I do need constructor for B.  And there would be many classes instead of one B because the general parser can parse any type of data depending upon tokens and inputs.  You took my example literally so you changed it completely.  I would like to pass references of static member string array from B to A if I could compile it :)
0
 
LVL 31

Author Comment

by:farzanj
ID: 38854767
ambience: Your answers are closest to what I wanted to ask, so far.
So, if I do not declare a default constructor, is it always protected? or private?
In general without declaring an access type what is default access type, protected or private?

I do not want to use global vector because I am still under the old notion that an array on the stack will be faster and I want as much speed as I can get.

I don't need char* array either because I need lengths of my tokens to be very handy as calculations will be based on them.

>>Also, from what I can understand, A's purpose is to copy arrays of objects. If you add const then you totally change the purpose of A.

No, as I explained above, it is just an example and I made it do something that would pass variables around so that I could get the syntax help.

My single class parser simply works great, I would use it directly by eliminating pure virtual function but parser has many different types and for each one I wanted to customize based on tokens and kind of output required using the object oriented way.
0
 
LVL 22

Assisted Solution

by:ambience
ambience earned 251 total points
ID: 38854843
>> So, if I do not declare a default constructor, is it always protected? or private?

If you supply a non-default constructor then there is no implicit default constructor (the default constructor is deleted - as per the new c++ standard). You must provide an implementation if you need it OR in the latest standards you can undelete it like

class A
{
A(int i); // non-default ctor
A() =  default; // ask compiler to generate default ctor
A(const A&) = default; // ask compiler to generate default copy ctor

...

If you do not supply any contructor in the class then the behavior is as if these were defined implicitly.

class A {
A() = default;
A(const A& ) = default;
.....

>> In general without declaring an access type what is default access type, protected or private?

private for class, public for struct
0
 
LVL 31

Author Comment

by:farzanj
ID: 38854979
So in my sub class, I want to declare tokens to be used by the parent class (A) so I don't mind if it is in a namespace or a global constant array or a static member variable of the subclass B but it should not be static in the parent (A) because parent will be used by multiple class and I don't want all instances of those to have the same token data.

Also, please feel free to comment on my use of const string array instead of vector due to speed or my design as I am trying to do the fastest design with best practices.

Appreciate your time and help.
0
 
LVL 22

Assisted Solution

by:ambience
ambience earned 251 total points
ID: 38855076
>> I want to declare tokens to be used by the parent class (A)

Perhaps its better to keep a pointer to token array in A (by default pointing to A's token array) but each subclass can set the pointer to a different token array in the ctor? I dont know if that even makes sense.

>> please feel free to comment on my use of const string array instead of vector due to speed or my design as I am trying to do the fastest design with best practices.

As far as the performance goes, only real benchmarks can tell you the difference - if theres any.

Theoretically, raw array access can be the faster (but as I mentioned it depends on how the rest of the code uses the array). For example, for a string array you need at least two levels  of indirection to reach the real buffer - first accessing the internal stringbuffer and then the pointer in it to the real chunk (most implementations are like that).

BUT .. how much faster? Unless a benchmark confirms the opposite I would say that a string array would be just as fast as a char* array.
0
 
LVL 31

Author Closing Comment

by:farzanj
ID: 38855488
Thank you all.  I will have follow up of this discussion.
0
 
LVL 33

Expert Comment

by:sarabande
ID: 38855495
your current design is that baseclass A gets two string arrays. the derived class B passes one global array and one array that was passed as an argument to B's constructor. the first array was individual for class B. if you would derive another class from A it could pass a different array. so my approach to make the first array a ststic member of A was wrong if you would enhance the sample code. it should be a static member of B instead.

class A
{
    std::vector<std::string> v1;
public:
    A(const std::vector<std::string> & s1) 
    {
          v1 = s1;   // v1 is now a copy of s1
    }
    void copy(std::vector<std::string>& s2)
    {
          s2 = v1;
    }
};

enum { num_vals = 10 };

class B : public A
{
       static const char * vals[num_vals];
public:
       B() : A(std::vector<std::string>(&vals[0], &vals[num_vals])) { } 
};

// static initialisation
const char * B::vals[num_vals] = {"first", "second", "third", "fourth", "Fifth", "6th", "7th", "8th", "9th", "10th", };

Open in new window


note the vals is an array of const char * because that allows static initialization (what is quite handy).

nevertheless you could initialize the vector member of A by use an appropriate constructor of std::vector.

the std::vector internally provides/uses a c array of the template type what in your case is an array of strings. so the difference of the performance of std::vector vs. c arrays is only in the overhead of calling a function instead of directly compiled code what is non-measurable even for big arrays.

but it has a lot advantages, for example it could have different number of elements depending on derived classes, what probably is a functionality you need.

note, neither A nor B should store a reference or pointer to the second array. it is much better design to pass the array with the copy function than to pass the array in the constructor and save it as a member. generally, class members should be encapsulated in the class. the variables hould not be created outside of the class nor should they made direct accessible from outside.

Sara
0
 
LVL 31

Author Comment

by:farzanj
ID: 38855689
Hi Sara,

Sorry, I had already closed this discussion.  It continues here:

http://www.experts-exchange.com/Programming/Languages/CPP/Q_28020557.html

I will reply to your comment there.
0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Python 2.7 - French characters 6 106
Arduino EDI - Programming language 3 104
Is there a canned solution for a custom genealogy website 2 101
Outlook 13 44
There is an easy way, in .NET, to centralize the treatment of all unexpected errors. First of all, instead of launching the application directly in a Form, you need first to write a Sub called Main, in a module. Then, set the Startup Object to th…
If you haven’t already, I encourage you to read the first article (http://www.experts-exchange.com/articles/18680/An-Introduction-to-R-Programming-and-R-Studio.html) in my series to gain a basic foundation of R and R Studio.  You will also find the …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

828 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