There are some major differences between C ++ and C #. One of them is the initialization syntax.
In C #, if you want to create a new type U that is either equal to or inferred from type T, you usually write:
T t = new U();
For value types (such as structures) you can also write:
T t;
Secondly, there is the problem of the lifetime of an object. With reference types, their lifetime is usually (excluding garbage collection / termination, for simplicity), the duration between the point they created, to the extent that they are not accessible from anywhere in the program. With value types, this is one and the same thing, except that value types are not garbage collected: they either “disappear” when their defining stack stack is returned, or when the object of the reference type from which they form part of the memory is “dead”.
With C ++, this is a different story.
In short, you have raw types that are somewhat equivalent to value types in C #. Then you have pointers and links that point to these types. There is much better information about what is happening here, but I am trying to explain enough background to answer your question.
So, if you hypothetically (provided that all types are defined) typed:
StreamWriter sr;
in C ++, you are essentially building a new StreamWriter object using its default constructor. Therefore, the definition is correctly formed only if StreamWriter has an available default constructor in this context.
If you typed:
StreamWriter sr = new StreamWriter();
You will get a compilation error because new StreamWriter() returns a pointer to the StreamWriter that you are trying to assign to the "actual" StreamWriter .
The correct way to enter this parameter (excluding best practices) would be
StreamWriter* sr = new StreamWriter();
The important distinction between raw types and pointers (or references) is indirect. Consider what happens in the following function:
void func() { StreamWriter sr = StreamWriter(); }
In this case, the stack frame for func() really needs to consume enough memory to contain the entire contents of the StreamWriter instance. That is, if it contains 4 32-bit integers as private members, then the stack frame will have to consume at least 16 bytes (4 * (32/8)).
So, if you want to access the StreamWriter element, there would be no indirectness. You would just read the memory with the offset of this member from the address of your sr variable, because &sr marks the beginning of the actual memory of the StreamWriter . The implication is that the sr variable can contain only StreamWriter and non-derived classes, since these derived classes may require more memory.
This is why I said that raw types are somewhat equivalent to C # value types because they share this behavior. If you have not noticed this before, C # structures cannot be inherited, and this should also explain or imply why this is so.
Now, in the case of the following function, using pointers:
void func() { StreamWriter* sr = ; }
Then, conceptually (excluding compiler optimization if appropriate), if you want to access a specific sr member, you need to follow these steps:
- Read the value of the
sr pointer. - Print the required offset of the element variable.
- Add result (1) with result (2) to get the member variable address contained in this particular
StreamWriter instance, or sr . - Read the number of bytes corresponding to the size of this member variable, starting with the value obtained from (3).
And the crucial point here is that there is indirection. Therefore, if sr now points to a StreamWriter derived class, then its basic memory layout will start just like StreamWriter , making the previous function still valid. This, by the way, is why polymorphism requires you to use pointers or references. There, the level of virtual calls was added and how it works, but so far it is a little inaccessible.
Now you must understand why
std::ostream s = new std::ostream() poorly formed.std::ostream s = std::ostream() or just std::ostream s does not work & mdash because std::ostream does not have an available default constructor.
What is lacking, however, is that my (2) here seems to contradict your observations:
std::ostream std::cout
And this is because this observation skips the key modifier in the actual one, which:
extern std::ostream std::cout;
Now, this is not a definition, but rather an declaration, that is, somewhere there an initialized variable in the std namespace called cout , which is of type ostream , and we leave it to the linker to figure where, although it can still use this variable.
This is hardly a minimal answer to your question, but I felt that it might be useful for you to analyze a little deeper. Enjoy learning C ++!
PS I touched on several aspects that really deserve more attention in terms of proper use. However, this will make this answer even longer.