Link to home
Start Free TrialLog in
Avatar of farzanj
farzanjFlag for Canada

asked on

C++ inheritance with pointers to array

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

Avatar of jkr
jkr
Flag of Germany image

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

Avatar of farzanj

ASKER

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

Avatar of farzanj

ASKER

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?
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

SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of farzanj

ASKER

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?
Avatar of farzanj

ASKER

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?
Avatar of farzanj

ASKER

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?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of farzanj

ASKER

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 :)
Avatar of farzanj

ASKER

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.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of farzanj

ASKER

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.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of farzanj

ASKER

Thank you all.  I will have follow up of this discussion.
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
Avatar of farzanj

ASKER

Hi Sara,

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

https://www.experts-exchange.com/questions/28020557/Differs-in-level-of-redirection.html

I will reply to your comment there.