The following is a class template that implements a stack using an array:
#include <iostream>
using namespace std;
template <typename T>
class stack {
public:
stack (int priv_size) {
T a[priv_size];
top = 0;
}
stack (const stack &s) {
T b[priv_size];
for (top=0; top<s.priv_size; top++) {
b[top] = s.a[top];
}
top++;
}
~stack () {}
const stack& operator = (const stack &s) {
T b[s.priv_size];
for (top=0; top<s.priv_size; top++) {
b[top] = s.a[top];
}
top++;
}
bool empty () {
return top == 0;
}
void push (const T &x) {
a[top++] = x;
}
T pop () {
T c = a[--top];
return c;
}
int size () {
return priv_size;
}
friend ostream& operator << (ostream &out, const stack &s) {
int i;
out << "[";
for (i=0; i<s.top-1; i++) {
out << s.a[i] << ", ";
}
if (i == s.top-1) out << s.a[s.top-1];
out << "]";
return out;
}
private:
int priv_size;
int top;
T a[];
};
int main () {
stack<int> s(10);
cout << "stack s is empty: " << s << endl;
s.push(42);
s.push(17);
cout << "stack s has 2 elements: " << s << endl;
cout << "Removing " << s.pop() << " from the stack..." << endl;
return 0;
}
However as i was trying out the different methods of the class in main I realized that although priv_size is initialized to the value of 10 here: stack<int> s(10); it loses its value right after the constuctor is called.
When i tried debugging in my IDE i realized that once the constructor stack (int priv_size) is called it created another variable priv_size that is initialized to the value of 10 instead of using the priv_size member of the class. The previous can also be seen here:
class member priv_size memory address (image)
and here:
unwanted variable priv_size memory address (image)
where the two variables are stored in different memory slots.
Why are the two variables different and why is the one in the second image created in the first place?
I have also tried implementing the class methods outside of the class, like this:
stack<T>::stack (int priv_size) {
T a[priv_size];
top = 0;
}
but i get these two error messages:
Member declaration not found
Type 'T' could not be resolved
What is going on here?
Thanks in advance.
PS: I am aware there are a couple very similar questions posted already, but the answers to those do not seem to fit my problem as my issue seems to be in the class itself and not in main or any other function.
Here are two links to some similar questions:
C++ Class members lose values assigned in a member function
Losing a data member of a base class after the constructor is called
stack (int priv_size) {
T a[priv_size];
top = 0;
}
Problem 1: Your constructor doesn't initialise the member a. It creates a local array.
Problem 2: The size of the array is not a compile time constant. The program is ill-formed.
Problem 3: You don't initialise the priv_size member either.
private:
int priv_size;
int top;
T a[];
Problem 4: You didn't specify size of the array member a. The program is ill-formed.
although priv_size is initialized to the value of 10 here: stack s(10); it loses its value right after the constuctor is called.
Your assumption is wrong. The constructor doesn't set the value of priv_size member, so no value was lost.
where the two variables are stored in different memory slots.
As far as I can tell, one variable is the parameter of the constructor and the other is the member variable that you didn't initialise.
Type 'T' could not be resolved
What is going on here?
To define a template, you need to use the keyword template and specify the template parameters. Like this for example:
template <typename T>
stack<T>::stack (int priv_size) {
Why are the two variables different and why is the one in the second image created in the first place?
Because you declared two different variables.
Its the same issue as in :
struct foo {
int x;
foo(int a) {
int x = a;
}
};
foos constructor declares a local variable named x which shadows the member x and the member x is not initialized. Same with an array:
struct bar {
int a[5];
bar() {
int a[5];
}
};
The member a and the a in the constructor are two distinct arrays.
This is only answering your question, but there are more problems in your code. When you need an array whose size is only known at runtime you should use std::vector.
There are multiple issues with your code. For instance, T a[priv_size]; requires that priv_size is a compile-time constant. And in stack (const stack &s) {T b[priv_size];, the local variable b goes out of scope when the copy ctor ends, while the member a remains uninitialized.
Related
This question already has answers here:
How to use a member variable as a default argument in C++?
(4 answers)
Closed 1 year ago.
I tried to set a default parameter to a member variable, it gave me this bug.
[cquery] invalid use of non-static data member 'num'
code
#include <iostream>
class Test{
private:
int val = 0;
public:
void print_num(int num = val){
std::cout << num << '\n';
}
}
int main(){
Test test;
test.print_num();
return 0;
}
Despite it being quite obvious what this would mean, you just can’t. The usual workaround is to provide an overload that (implicitly) uses this to get the member value.
In order to set a default value for a function parameter to a class member, the member must be static.
Citing the documentation,
Non-static class members are not allowed in default arguments
However, given the context of your code sample I doubt this is what you want to do (as every instance of Test class will point to the same val. Citing the docs:
Static members of a class are not associated with the objects of the class: they are independent variables
If you make val static in your example, and have multiple instances of Test in use by your code, you can (and very likely will) have some unexpected behavior. Consider:
#include <iostream>
class Test{
private:
static int val;
public:
void print_num(int num = val){
std::cout << num << '\n';
}
void set_val(int num) {
val = num;
}
}
int Test::val = 0;
int main(){
Test test1;
test1.set_val(1);
Test test2;
test2.set_val(2);
test1.print_num(); // results in "2"
return 0;
}
A better alternative would be to pass a pointer to your function like this:
#include <iostream>
class Test{
private:
int val = 0;
public:
void print_num(int* numptr = nullptr){
int num = (numptr ? *numptr : val);
std::cout << num << '\n';
}
}
int main(){
Test test;
test.print_num();
return 0;
}
Or, as described by Davis Herring, use an overload:
#include <iostream>
class Test{
private:
int val = 0;
public:
void print_num(int num){
std::cout << num << '\n';
}
void print_num() {
return print_num(val); // return is irrelevant here, but my preferred coding style
}
}
int main(){
Test test;
test.print_num();
return 0;
}
Edited to reflect the comment and example.
Your function definition doesn't actually know what val is because it doesn't actually live inside of your class. The compiler is actually making a function that contains your class as a parameter and abstracts away all of that. You'll want to set num to val within the function body.
I have recently read something like this. I konw it is not so complex. But as a beginner, I just don't know why it works, so here is the description.
#include <list>
#include <iostream>
using namespace std;
template <typename T>
class A
{
public:
list<T *> testlist;
A();
~A();
void m_append(T* one);
};
template <typename T>
A<T>::A()
{
cout << "constructor" << endl;
}
template <typename T>
A<T>::~A()
{
cout << "destructor" << endl;
}
template <typename T>
void A<T>::m_append(T* one)
{
cout << *one << " push in" << endl;
testlist.push_back(one);
}
int main(void)
{
A<int> a;
int b = 4;
int c = 5;
int d = 6;
a.m_append(&b);
a.m_append(&c);
a.m_append(&d);
return 0;
}
In my opinion this testlist is not initialized, there should be something wrong.
But it works.
constructor
4 push in
4
5 push in
5
6 push in
6
destructor
So I am pretty confused. There is no need to initialize this testlist or?
Data member testlist is not mentioned in the member initializer list of constructor of A, and doesn't have default member initializer (since C++11), then it would be default initialized via the default constructor of std::list.
when a base class or a non-static data member is not mentioned in a constructor initializer list and that constructor is called.
And
There is no need to initialize this testlist or?
It depends on your intent. If the default initialization is enough, then yes.
To understand this, you must know how a list is constructed.
It has a control block on the stack and then allocates elements on the heap if you insert elements. The control block is initialized by the constructor.
Here is a picture to understand how this looks like:
So you don't need to initialize the list.
I'm creating a static variable 'a' inside a member function getobj() and returning it by reference and capture the reference in b. And I modify the same static variable 'a' in another member function mod(). When I print b, I should be expecting '2' right? Why isn't the static variable 'a' not modified to 2?
#include <iostream>
using namespace std;
class Test {
public:
int& getobj() {
static int a = 1;
return a;
}
void mod() {
static int a = 2;
}
};
int main(int arc, char* args[]) {
Test t;
int &b = t.getobj();
cout << "printing b first time and its value is expected : " << b << endl;
t.mod();
cout << "printing b second time after modifying and its value has not changed : " << b << endl;
return 0;
}
Output observed is
printing b first time and its value is expected : 1
printing b second time after modifying and its value has not changed : 1
The variable a in getobj() and the variable a in mod() are in different scope and are different things.
Therefore, modification to a in mod() won't affect a in getobj().
You could achieve your aim with the following piece of computational devilry:
void mod() {
static int& a = getobj();
a = 2;
}
Currently you have two different ints, both with static storage. Changing one will not change the other.
But did you want to use a class member variable instead (which is the normal thing to do), perhaps even without static storage duration?
class test {
public:
static int n;
test () { n++; };
~test () { n--; };
};
int test::n=0; //<----what is this step called? how can a class be declared as an integer?
int main () {
test a;
test b[5]; // I'm not sure what is going on here..is it an array?
test * c = new test;
cout << a.n << endl;
delete c;
cout << test::n << endl;
}
secondly, the output is 7,6 I'm not understanding how did it get 7, from where?
From the statement-
int test::n=0;
'::' is called scope resolution operator. This operator is used here to initialize the static field n, not the class
Static data members are declared in class. They are defined outside the class.
Thus in the class definition
class test {
public:
static int n;
test () { n++; };
~test () { n--; };
};
record
static int n;
only declares n. You need to define it that is to allocate memory for it.
And this
int test::n=0;
is its definition. test::n is a qualified name of the variable that denotes that n belongs to class test.
According to the class definition when an object of the class is constructed this static variable is increased
test () { n++; };
And when an object is destructed this static variable is decreased
~test () { n--; };
In fact this static variable plays a role of counting alive objects of the class.
Thus in main you defined object of the class with name a
test a;
Each time an object is defined the constructor of the class is called. Consequently n was increased and becomes equal to 1.
Adter defining array of 5 objects
test b[5];
n becomes equal to 6.
After dynamically allocating one more object
test * c = new test;
n becomes equal to 7.
After its explicit deleting
delete c;
n again becomes equal to 6 because called destructor decreased n.
I have been working on a code in C++. But, I got stuck at a point.
This is a small prototype of my code::
#include <iostream>
using namespace std;
class Test{
private:
const int var;
void funPrivate(int arr[][var], int temp){
cout << arr[0][0] << endl;
}
public:
Test(int n) : var(n){};
void funPublic(){
int a[var][var];
funPrivate(a, var);
cout << "Hello";
};
};
int main()
{
Test t1(5);
t1.funPublic();
return 0;
}
I create a class funPublic() method, where I create a 2D array (using the const int var, which I declare as a private member inside my class Test) and then pass it to a private methode funPrivate(int arr[][var], int temp), where I print arr[0][0] (which shall be a garbage value).
But, when I try to run this program, I get an error::
error: invalid use of non-static data member 'Test::var'
My method funPrivate(int arr[][var], int temp) is a normal function (not a static function) and I don't a reason that I shall declare int var as static. Why does this happen.
Further, if I slightly modify the declaration of my method 'funPrivate(int arr[][var], int temp)' to this void funPrivate(int arr[][var]) then I get one more error:
error: 'arr' was not declared in this scope
Now, I don't know why does that happen. We pass the size of the array for our convenience, because there is no way to determine the size of the array in a function, but that shall not cause the error that arr was not declared in this scope.
I have been thinking and searching a lot, but still can't find an answer. Please help. Thanks for any help in advance. :D
The member variable var cannot be used in the declaration of an array like you are attempting in the function funPrivate:
void funPrivate(int arr[][var], int temp)
Your best option is to use std::vector<std::vector<int>>.
void funPrivate(std::vector<std::vector<int>> const& arr, int temp) {
cout << arr[0][0] << endl;
}
In the calling function, you can use:
void funPublic(){
std::vector<std::vector<int>> arr(var, std::vector<int>(var));
funPrivate(arr, var);
cout << "Hello";
};