0

I'm porting over C code to C++ and I'm having an issue with dynamic array initialization. The code below is a simplified version of the problem. Why is there an error if maxSize is declared within the class yet it's fine if declared outside of it?

EDIT: Why isn't there a solution similar to the simplicity of adding static int maxSize; outside of the class? That's probably bad practice for reasons rarely mentioned so what would the next best solution be that requires the least amount of modification to the rest of the methods in the bTree class?

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

using std::cout;
using std::endl;
using std::string;
using std::vector;

//int maxSize = 3;

class bTree
{
private:

    int maxSize = 3; // this variable is fine outside of the class but not within it..


    struct Item{
        string key;
        string value;
    };

    struct Node{
        int count;
        vector<Item> items;
        Node **branch;

        Node() : items(maxSize + 1) // error C2327: 'bTree::maxSize' : is not a type name, static, or enumerator

        {
            branch = new Node*[maxSize + 1];  // error C2327: 'bTree::maxSize' : is not a type name, static, or enumerator
        }
    };

    // .... other variables....

public:
    bTree(int size)
    {
        maxSize = size;
    }

    ~bTree(){}

    // ...other methods...

};

int main(int argc, char *argv[])
{
    bTree *bt = new bTree(5);
    return 0;
}
John
  • 31
  • 4
  • `bTree *bt = new bTree(5);` C++ is not Java: All you need is: `bTree bt(5);` – PaulMcKenzie Apr 12 '15 at 01:27
  • In C++ nested class cannot see fields defined in its outer class as in Java because nested class can be instantiated independently of the outer class. If you want, you need to manually pass an instance of the outer class, to the inner. – findall Apr 12 '15 at 01:36
  • `maxSize` should surely be a constant. – user207421 Apr 12 '15 at 02:24
  • maxSize will be set when the class is instantiated so it can't be constant. It apparently can't be static either since it causes a LNK2001 error... – John Apr 12 '15 at 02:25
  • @John a`static` class member variable must be declared *and* defined in one and only one module. http://stackoverflow.com/questions/185844/initializing-private-static-members But seriously, look at all the STL containers -- you see no `static` variables, and many are more complex than your `btree`. Ask yourself "why is that?" Also, see my comment in one of the answers given. – PaulMcKenzie Apr 12 '15 at 02:38

3 Answers3

1

You are trying to access a member that is not in the scope of the Node class. One fix is to so something similar to this:

struct Node{
     //...
        std::vector<Items> items;
        Node(int m) : items(m + 1), branch(new Node*[m]()) {}
};

Another thing is that you should use std::vector when possible. Your Node class does not need to use dynamically allocated memory:

struct Node{
     //...
        std::vector<Item> items;
        std::vector<Node*> branch;
        Node(int m) : items(m + 1), branch(m) {}
};
PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • Why isn't there a solution as simple as adding static int maxSize; outside of the class? That's probably bad practice for reasons rarely mentioned so what would the next best solution be that requires the least amount of modification to the rest of the methods in the bTree class? – John Apr 12 '15 at 02:38
  • See my other comments. The `static` variable is *shared* between instances of a `btree`. You can't have two different `btrees` with differing maximum sizes. Also, the "simplest" solution to clean up your room is to stuff the dirt under the rug. Does that make the room clean? Same analogy. – PaulMcKenzie Apr 12 '15 at 02:41
0

The problem is that unlike java inner classes struct Node doesn't have a pointer to outer class bTree. That means that when the constructor of Node is called there is no visible variable bTree::maxSize to use. You have to explicitly pass maxSize as an argument to constructor. Another option is to make this variable static (but it looks for me that it is not suitable in your case because you want different maxSize for different instances of bTree).

EDIT: In case if you are interested how to use static field here:

class bTree
{
public:
    static void setMaxSize(int maxSize)
    {
        bTree::maxSize = maxSize;
    }
    bTree()
    {}
private:
    static int maxSize = 3;
    /* ... */
    struct Node
    {
        /* ... */
        Node()
             : items(maxSize + 1)
             , branch(new Node*[maxSize + 1])
        {}
    }
}


int main()
{
    // bTree::setMaxSize(5);
    bTree bTree;
    return 0;
}
antonpp
  • 2,333
  • 23
  • 28
  • There will only be one instance of bTree used in a separate main.cpp file. Node and Item are only used by the bTree class also. Isn't a static variable bad practice? What should be done to fix this? – John Apr 12 '15 at 01:31
  • @John, word static has several meanings in c++. Static field in class is not a bad practice. As an example, it is the way to implement singletons. – antonpp Apr 12 '15 at 01:34
  • It seems like the answer is just to add the static keyword to the maxSize variable within the class. Adding the static keyword is the simplest fix and doesn't require modifying the rest of the code. It seems like the obvious answer but I'm suspicious that it may be bad practice since it wasn't mentioned. I get a error when I do that though: Error 1 error LNK2001: unresolved external symbol "private: static int bTree::maxSize" – John Apr 12 '15 at 02:11
  • @John The issue with the static variable inside your class is that `btree` must have size 3 at all times. If for some reason that static is changed to another number, the `maxsize` no longer reflects what the maximum size of the tree is. Just because a fix seems "the simplest", doesn't mean that it is the best. Also, `static` is shared between instances -- you can't have a btree with max size of 10 and another with max size of 100, for example. – PaulMcKenzie Apr 12 '15 at 02:34
0

Another option:

You can put the struct definitions outside the class and define class data members of their types (Item, Node) and initialize them in your class constructor. For example:

    struct Item{
        string key;
        string value;
    };

    struct Node{
        int count;
        int maxSize;
        vector<Item> items;
        Node **branch;

        ...
    };

class bTree
{
private:

    int maxSize = 3; 
    Item item;
    Node node;

public:
    bTree(int size)
    {
        maxSize = size;
        node.maxSize = size; // OR you may call a member function or constructor of Node struct.
        ...
    }

    ~bTree(){}

    // ...other methods...

};
erol yeniaras
  • 3,701
  • 2
  • 22
  • 40
  • Why isn't there a solution similar to the simplicity of adding static int maxSize; outside of the class? That's probably bad practice for reasons rarely mentioned so what would the next best solution be that requires the *least* amount of modification to the rest of the methods in the bTree class? – John Apr 12 '15 at 02:39