Reputation: 2406
While trying to familiarize myself with c++ and its concepts, I came across the
using namespace std
and
#include <iostream>
my simple code is as follows
#include "stdafx.h"
#include "ConsoleApplication5.h"
#include <iostream>
int main()
{
std::cout << "hi";
return 0;
}
Using Visual Studio 2015 Community, which uses intellisense, shows
cout
uses the following
std::ostream std::cout
As a C# programmer, this confuses me slightly. Is this :
std::ostream
being a return type while
std::cout
being the method/parameter passed or is
std::ostream
a dependancy of
cout
UPDATE (after Archimaredes Answer)
In C#, one can use the following:
StreamWriter srWrite;
or
StreamWriter srWrite = new StreamWriter(string filepath)
or one can use:
StreamWriter srWrite = new StreamWriter(new NetworkStream(Socket.GetStream()));
Each case a object of type namely
StreamWriter
is assignable with a new object or a existing file or a networkstream.
I tried the same after that which you mentioned (excuse the C# mentality) with the std::ostream x = new std:ostream
which returns a no default constructor.
Could you just add how std::ostream and std::cout relate to each other, which creates/initalizes the other. THis concept is still a bit vague to me.
Upvotes: 5
Views: 1219
Reputation: 8141
There are some basic differences between C++ and C#. One of them is initialization syntax.
In C#, if you want to create a new type U which either equals or is derived from a type T, you generally write:
T t = new U();
For value-types (such as structs), you can also write just:
T t;
Secondly, there's the issue of object lifetime. With reference-types, their lifetime is, generally (excluding garbage collection/finalization, for simplicity), the duration between the point they're created to the point they're inaccessible from anywhere in the program. With value-types, it's the same thing, except that value-types aren't garbage-collected by themselves: they either "vanish" when their defining stack frame returns, or when the reference-type object of which they form part of the memory is "dead."
With C++, it's a different story.
Loosely speaking, you have "raw" types, which are to some extent equivalent to value-types in C#. Then you have pointers and references, which point to such types. There are much better accounts of what's going on here, but I'm trying to explain just enough background to answer your question.
So, if you hypothetically (assuming all types are defined) typed:
StreamWriter sr;
in C++, you'd essentially be constructing a new StreamWriter
object, using its default constructor. Hence, the definition is well-formed only if StreamWriter
has an accessible default constructor in that context.
If you typed:
StreamWriter sr = new StreamWriter();
You would get a compilation error, because new StreamWriter()
returns a pointer to a StreamWriter
, which you're trying to assign to an "actual" StreamWriter
.
The correct way to type this (excluding best-practices for now), would be
StreamWriter* sr = new StreamWriter();
The important difference between "raw" types and pointers (or references) is indirection. Let's consider what would happen in the following function:
void func() {
StreamWriter sr = StreamWriter();
}
In this case, the stack frame for func()
would actually need to consume enough memory to contain the whole contents of a StreamWriter
instance. That is, if it contained 4 32-bit integers as private members, then the stack frame would have to consume at least 16 bytes (4 * (32 / 8)).
So if you wanted to access a member of StreamWriter
, there wouldn't be any indirection. You would just read the memory at the offset of that member from the address of your sr
variable, because &sr
denotes the start of the actual StreamWriter
object memory. The implication is that the variable sr
can only safely contain StreamWriter
, and no derived classes, since those derived classes might require more memory.
This is why I said "raw" types are somewhat equivalent to C# value types, because they share this behavior. If you hadn't noticed it before, C# structs cannot be inherited, and this should also serve to explain, or imply, why that is so.
Now, in the case of the following function, using pointers:
void func() {
StreamWriter* sr = /*...*/;
}
Then, conceptually (excluding compiler optimizations in eligible cases), if you wanted to access a certain member of sr
, you would have to take the following steps:
sr
.StreamWriter
instance, or sr
.And the crucial point here, is that there's an indirection. So if sr
now pointed to a derived class of StreamWriter
, then its basic memory layout would start out just like StreamWriter
's, making the previous function still work correctly. This, by the way, is why polymorphism requires you to use either pointers or references. There's an added level of virtual calls and how that works, but that's a bit out of scope for now.
By now you should realize why
std::ostream s = new std::ostream()
is ill-formed.std::ostream s = std::ostream()
or simply std::ostream s
wouldn't work—because std::ostream
has no accessible default constructor.What's missing, though, is that my (2) here seems to conflict with your observing:
std::ostream std::cout
And that's because that observation misses a crucial modifier in the actual one, which is:
extern std::ostream std::cout; // note 'extern'
Now, that's not a definition, rather it's a declaration, that—somewhere—there's an initialized variable in the namespace std
called cout
which is of type ostream
, and we leave it to the linker to figure out where, while still being able to make use of that variable.
This is hardly a minimal answer to your question, but I felt like you might benefit from a slightly deeper analysis. Enjoy learning C++!
P.S. I touched on several aspects here which really deserve more attention in and of themselves, as far as proper usage goes. However, that would make this answer even longer.
Upvotes: 3
Reputation: 1427
std::cout
is an object in global scope, of type std::ostream
. When you call std::cout << "hi"
, you are invoking the operator<<()
method with the std::cout
object as your left-hand value and the string literal "hi"
as the right-hand value.
cout
and ostream
are inside the std
namespace, hence the std::
prefix. If you place using namespace std
in your code, this allows you to omit the prefixes, e.g.
#include <iostream>
using namespace std;
int main() {
cout << "hi"; // no error because the 'std' is unnecessary now
}
Namespaces are used to prevent name conflicts, in exactly the same way as C#; it is usually good practice to not use using namespace
directives for entire source code files in order to prevent name conflicts in your code.
Edit in response to OP's update
std::cout
is an instance of std::ostream
. To illustrate this, consider the following:
class A_Class {
public:
A_Class() {}
void foo() {}
};
int main() {
A_Class an_instance;
an_instance.foo();
}
A_Class
is a class, while an_instance
is an instance of A_Class
.
Similarly; ostream
is a class, while cout
is an instance of ostream
.
Edit in response to OP's comments
This may look confusing to a user of C#, but it is the exact same concept as:
int n = 5;
Whereint
is the type, and n
is the variable name.
Upvotes: 7