在尝试熟悉c ++及其概念时,我遇到了
using namespace std
和
#include <iostream>
我的简单代码如下
#include "stdafx.h"
#include "ConsoleApplication5.h"
#include <iostream>
int main()
{
std::cout << "hi";
return 0;
}
使用使用智能感知的Visual Studio 2015社区显示
COUT
使用以下
std :: ostream std :: cout
作为一名C#程序员,这让我有点困惑。是这样的:
的std :: ostream的
是
时的返回类型的std :: COUT
是传递的方法/参数或是
的std :: ostream的
的依赖性
COUT
更新(在Archimaredes回答之后)
在C#中,可以使用以下内容:
StreamWriter srWrite;
或
StreamWriter srWrite = new StreamWriter(string filepath)
或者可以使用:
StreamWriter srWrite = new StreamWriter(new NetworkStream(Socket.GetStream()));
每种情况都是一种类型的对象,即
StreamWriter
可以使用新对象或现有文件或网络流进行分配。
我在使用std::ostream x = new std:ostream
返回no默认构造函数的{{1}}之后尝试了同样的事情(请原谅C#心态)。
你能不能添加std :: ostream和std :: cout如何相互关联,这会创建/初始化另一个。这个概念对我来说仍然有点模糊。
答案 0 :(得分:7)
std::cout
是全局范围内的对象,类型为std::ostream
。当您致电std::cout << "hi"
时,您正在调用operator<<()
方法,其中std::cout
对象为左侧值,字符串文字"hi"
为右侧值。< / p>
cout
和ostream
位于std
命名空间内,因此是std::
前缀。如果您在代码中放置using namespace std
,则可以省略前缀,例如
#include <iostream>
using namespace std;
int main() {
cout << "hi"; // no error because the 'std' is unnecessary now
}
命名空间用于防止名称冲突,与C#完全相同;对于整个源代码文件,不使用using namespace
指令通常是一种好习惯,以防止代码中出现名称冲突。
根据OP的更新进行编辑
std::cout
是std::ostream
的实例。为了说明这一点,请考虑以下事项:
class A_Class {
public:
A_Class() {}
void foo() {}
};
int main() {
A_Class an_instance;
an_instance.foo();
}
A_Class
是一个类,而an_instance
是A_Class
的实例。
类似地; ostream
是一个类,而cout
是ostream
的实例。
根据OP的评论进行编辑
这可能让C#的用户感到困惑,但它的概念完全相同:
int n = 5;
其中int
是类型,n
是变量名称。
答案 1 :(得分:3)
C ++和C#之间存在一些基本差异。其中之一是初始化语法。
在C#中,如果要创建一个等于或来自类型T的新类型U,通常会写:
T t = new U();
对于值类型(例如结构),您也可以只写:
T t;
其次,存在对象生命周期的问题。对于引用类型,它们的生命周期通常(不包括垃圾收集/完成,为简单起见),它们创建点到程序中任何地方都无法访问的时间。对于值类型,它是相同的,除了值类型本身不是垃圾收集:它们或者在它们定义的堆栈帧返回时“消失”,或者当它们构成它们的引用类型对象时记忆是“死的”。
使用C ++,这是一个不同的故事。
松散地说,你有“原始”类型,这在某种程度上等同于C#中的值类型。然后你有指针和引用,指向这些类型。关于这里发生了什么有更好的说明,但我试图解释足够的背景来回答你的问题。
因此,如果您假设(假设所有类型都已定义),请键入:
StreamWriter sr;
在C ++中,你基本上是使用它的默认构造函数构造一个新的StreamWriter
对象。因此,只有StreamWriter
在该上下文中具有可访问的默认构造函数时,该定义才是格式良好的。
如果您输入:
StreamWriter sr = new StreamWriter();
您会收到编译错误,因为new StreamWriter()
会将指针返回给StreamWriter
,您尝试将其分配给“实际”StreamWriter
}。
键入此内容的正确方法(目前不包括最佳做法)将是
StreamWriter* sr = new StreamWriter();
“原始”类型和指针(或引用)之间的重要区别是间接。让我们考虑以下函数会发生什么:
void func() {
StreamWriter sr = StreamWriter();
}
在这种情况下,func()
的堆栈帧实际上需要消耗足够的内存来包含StreamWriter
实例的全部内容。也就是说,如果它包含4个32位整数作为私有成员,那么堆栈帧必须消耗至少16个字节(4 *(32/8))。
因此,如果您想访问StreamWriter
的成员,则不会有任何间接。您只需从sr
变量的地址读取该成员的偏移量,因为&sr
表示实际StreamWriter
对象内存的开头。这意味着变量sr
只能安全地包含StreamWriter
,并且没有派生类,因为这些派生类可能需要更多内存。
这就是为什么我说“原始”类型在某种程度上等同于C#值类型,因为它们共享这种行为。如果您之前没有注意到,C#结构不能被继承,这也应该用于解释或暗示为什么会这样。
现在,在以下函数的情况下,使用指针:
void func() {
StreamWriter* sr = /*...*/;
}
然后,从概念上(在符合条件的情况下排除编译器优化),如果您想访问某个sr
成员,则必须执行以下步骤:
sr
。StreamWriter
实例中包含的成员变量的地址,或sr
。这里的关键点是,有一个间接性。因此,如果sr
现在指向派生的类StreamWriter
,那么它的基本内存布局就会像StreamWriter
一样开始,使前一个函数仍然存在工作正常。顺便说一下,这就是多态性要求你使用指针或引用的原因。有一个额外的虚拟调用级别以及如何工作,但现在有点超出了范围。
到现在为止你应该意识到为什么
std::ostream s = new std::ostream()
格式不正确。std::ostream s = std::ostream()
或只是std::ostream s
无效 - 因为std::ostream
没有可访问的默认构造函数。但遗漏的是,我的(2)似乎与你的观察相冲突:
std::ostream std::cout
那是因为观察错过了实际的一个关键修饰符,即:
extern std::ostream std::cout; // note 'extern'
现在,这不是定义,而是声明,在某处 - 名称空间std
中有一个名为{{1}的初始化变量类型为cout
的类型,我们将它留给链接器来找出 where ,同时仍然可以使用该变量。
这对你的问题几乎不是一个简单的答案,但我觉得你可能会从稍微深入的分析中受益。喜欢学习C ++!
P.S。我在这里谈到了几个方面,就适当的用法而言,它们本身应该得到更多的关注。但是,这会使这个答案更长。