c ++ - 使用std命名空间和依赖项

时间:2016-01-27 12:39:39

标签: c# c++ c++11

在尝试熟悉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如何相互关联,这会创建/初始化另一个。这个概念对我来说仍然有点模糊。

2 个答案:

答案 0 :(得分:7)

std::cout是全局范围内的对象,类型为std::ostream。当您致电std::cout << "hi"时,您正在调用operator<<()方法,其中std::cout对象为左侧值,字符串文字"hi"为右侧值。< / p>

coutostream位于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::coutstd::ostream实例。为了说明这一点,请考虑以下事项:

class A_Class {
public:
    A_Class() {}
    void foo() {}
};

int main() {
    A_Class an_instance;
    an_instance.foo();
}

A_Class是一个类,而an_instanceA_Class的实例。

类似地; ostream是一个类,而coutostream的实例。

根据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成员,则必须执行以下步骤:

  1. 读取sr
  2. 的指针值
  3. 推断所需的成员变量偏移。
  4. 使用(2)的结果添加(1)的结果,以获取该特定StreamWriter实例中包含的成员变量的地址,或sr
  5. 从(3)获得的值开始,读取与该成员变量大小对应的字节数。
  6. 这里的关键点是,有一个间接性。因此,如果sr现在指向派生的StreamWriter,那么它的基本内存布局就会像StreamWriter一样开始,使前一个函数仍然存在工作正常。顺便说一下,这就是多态性要求你使用指针或引用的原因。有一个额外的虚拟调用级别以及如何工作,但现在有点超出了范围。

    到现在为止你应该意识到为什么

    1. std::ostream s = new std::ostream()格式不正确。
    2. std::ostream s = std::ostream() 只是std::ostream s无效 - 因为std::ostream没有可访问的默认构造函数。
    3. 但遗漏的是,我的(2)似乎与你的观察相冲突:

      std::ostream std::cout
      

      那是因为观察错过了实际的一个关键修饰符,即:

      extern std::ostream std::cout; // note 'extern'
      

      现在,这不是定义,而是声明,在某处 - 名称空间std中有一个名为{{1}的初始化变量类型为cout的类型,我们将它留给链接器来找出 where ,同时仍然可以使用该变量。

      这对你的问题几乎不是一个简单的答案,但我觉得你可能会从稍微深入的分析中受益。喜欢学习C ++!

      P.S。我在这里谈到了几个方面,就适当的用法而言,它们本身应该得到更多的关注。但是,这会使这个答案更长。