1

I'm coming (very recently) from C#, where I am used to instantiating objects like this:

Phone myPhone = new Phone();

simply writing

Phone myPhone;

essentially creates a holder for a class, but it is yet to be initialised so to speak.

now I'm writing a small class in C++ and I have a problem. Here is the pseudo code:

Phone myPhone;

void Initialise()
{
    myPhone = new Phone();
}

void DoStuff()
{
    myPhone.RingaDingDong();
{

In fact this is a little misleading as the above code is what I would LIKE to have, because I want to be able to put all my initialisation code for lots of things into one neat place. My problem is that the line inside initialise is unnecessary in C++, because before that, a new instance is already created and initialised by the very first line. On the other hand if I put the just the first line inside Initialise() I can no longer access it in DoStuff. It is out of scope, (not to mention the differences between using 'new' or not in C++). How can you create simply a holder for a class variable so I can initialise it in one place, and access it in another? Or am I getting something fundamentally wrong?

Thanks in advance!

Dollarslice
  • 9,917
  • 22
  • 59
  • 87
  • 3
    I've tried to write an answer, but the question involves too much stuff. So instead, standard SO C++ response #1: [read a good intro book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Cat Plus Plus Sep 23 '11 at 11:55
  • Agreed with CPP here. Knowing one particular mechanic of a language is one thing, but that's a long shot from understanding the language's idioms. Unfortunately your example is far too short and isolated to give meaningful advice, so I'll leave it with a conditional "don't use `new` or pointers". – Kerrek SB Sep 23 '11 at 12:03

5 Answers5

2

You can use the new operator on a pointer:

Phone *myPhone;

void Initialise()
{
    myPhone = new Phone();
}

void DoStuff()
{
    myPhone->RingaDingDong();
}

The only two changes are the added * in the declaration of myPhone and the -> instead of . when accessing RinaDingDong(). You will also have to free it since new is allocating memory:

void destroy()
{
    delete myPhone;
}

Note that if you do this myPhone will be a pointer to a Phone not an actual Phone.

flight
  • 7,162
  • 4
  • 24
  • 31
  • probably more what OP is going for. – Ramy Sep 23 '11 at 11:54
  • 4
    Except you shouldn't use raw pointers, or the free store, unless you actually need it. – Cat Plus Plus Sep 23 '11 at 11:56
  • awesome, ok great. Still adjusting to using pointers, and now i'm understanding why so many globals in examples are pointers. One question - am I right in assuming that Phone myPhone; has sort of a built in 'new' inside, but one that the compiler keeps track of so you don't need to call 'delete'? – Dollarslice Sep 23 '11 at 11:58
  • @CatPlusPlus is there a way to do what I want to do without using 'new'? – Dollarslice Sep 23 '11 at 11:59
  • @SirYakalot: It's called an automatic variable, and is destroyed when it exits the scope. – Cat Plus Plus Sep 23 '11 at 12:00
  • @SirYakalot Yes, when you declare a phone "normally" like that, you don't have to explicitly delete it. – flight Sep 23 '11 at 12:00
  • @SirYakalot: I don't know what you want to do. Always start with automatic variables, and move to pointer stuff only when you absolutely can't make it work otherwise. – Cat Plus Plus Sep 23 '11 at 12:01
  • 2
    @SirYakalot: While this question is technically correct, it does rather miss the point that this is not how C++ is usually spoken. C++ distinguishes automatic and dynamic object lifetime, and there is almost never a need to manually create a dynamic object (as you do with `new`). Automatic variables suffice in most situations, and for everything else it is preferable to use a resource-managing container class. – Kerrek SB Sep 23 '11 at 12:02
  • The way to do it without `new` is to just allocate it on the stack (which means its lifetime is the same as the function's) or as a global (which means its constructor runs before `main()` and destructor runs after main()). You don't have to remember to `delete` if you don't use `new`. Also, slight nitpick to quasi's answer: You use `new` on a class name to get a pointer, you don't use it on a pointer. Finally, if you use a `Phone*` instead of a `Phone`, then it can be a pointer to any subclass of `Phone` (say, `AndroidPhone`), but if you declare a `Phone` you only get a `Phone`. – Mike DeSimone Sep 23 '11 at 12:05
  • thanks for all your help. One thing though, if I remove the initialise method from qasiverse's answer, it still works. So what exactly do I need the 'new' expression for? – Dollarslice Sep 23 '11 at 12:10
  • @SirYakalot: It does not work. It invokes Undefined Behaviour. It just compiles. However, in C++ in the general case, you *should* use automatic life-time variables. – Puppy Sep 23 '11 at 14:49
2

If your Phone constructor takes no parameters then your life is pretty simple - you don't need to new up the phone in the Initialize method. It will be created for you when the object is created and the lifetime will be managed for you.

If you need to get parameters to it, and it doesn't have an Initialize() method or some set methods, then you may need to use a pointer (which can sometimes be null) and have Initialize() call new and pass in those parameters. Your other code needs to check if the pointer is null before using it. Also you need to manage lifetime (by writing the big 3) or use a smart pointer such as shared_ptr from C++11. This should not be your first choice.

Kate Gregory
  • 18,808
  • 8
  • 56
  • 85
0

I think you need to brush a bit on pointers. What you are trying to do is possible with pointers.

My problem is that the line inside initialise is unnecessary in C++, because before that, a new instance is already created and initialised by the very first line.

This is incorrect. The comment provided by you only holds good for constructors. From your puesdo code, the function initialize is a global function and is not a member function of a class.

On the other hand if I put the just the first line inside Initialise() I can no longer access it in DoStuff. It is out of scope, (not to mention the differences between using 'new' or not in C++).

Please refer any book on pointers, you can have a global pointer and initialize with new. This can be used in doStuff

kumar_m_kiran
  • 3,982
  • 4
  • 47
  • 72
  • 2
    I believe that when he said "a new instance is already created", he was referring to this: `Phone myPhone;` – flight Sep 23 '11 at 11:57
0

If your coming from C#, you know that you have two types of object: class and struct.

The class are copied, assigned and passed to function by reference. So, they are using a reference semantic. The class are also allocated in the heap (using new).

The struct are implementing a value copy semantic. Struct are allocated on the stack (int, double and other built-in type are struct). You cannot treat struct polymorphicaly.

In C++ you haven't got this difference. Class and struct are essentially the same (a part the default access level). It is not the declaration of the class to determinate the copy semantic but it is the declaration of the instance to a class.

If you create a pointer the behaviour is very similar to a class in c#. If you create an object the semantic will be similar to a struct in c#.

C++ has also reference, you should read about the difference between pointers and references.

Alessandro Teruzzi
  • 3,918
  • 1
  • 27
  • 41
0

Kate Gregory's answer is the right one, but I wanted to elaborate a little bit. One of the more powerful ideas in C++ is that stack-allocated objects are owned by their containing scope. For example, if you want to write a class which contains a phone, you'd just write this:

class Secretary { 
    Phone myPhone;
};

And now every time a Secretary is created, a Phone object is automatically initialized with its default constructor. More importantly, whenever a Secretary object is destroyed, its contained Phone object is also destroyed. If you want to use a different constructor for the Phone, you can use initializer lists in Secretary's constructor:

class Secretary {
private: // members
    Phone myPhone;
    Phone myCellPhone;

public: // methods
    Secretary() : myPhone("phone constructor", 12, " args") {}
};

In this case myPhone is initialized using its 3-argument constructor, and myCellPhone is initialized using its default constructor as usual.

eplawless
  • 4,225
  • 7
  • 34
  • 35