java.lang.Object x = new Foo()
的C ++等价物是什么?
答案 0 :(得分:19)
在C ++中没有相同的东西,尝试用C ++编写Java是没有意义的。话虽如此,我将从试图模仿尽可能多的赋值特征和陈述精神的角度来处理这个问题。我建议的每种方式都有缺点和局限。前两个并不是真正惯用的C ++,但重要的是要了解它们,看看最后两个问题解决了什么。
<强> 1。 C风格的无效指针。
让我从最基本和最不实用的空指针开始:
void* foo = new Foo();
任何东西都可以分配给new运算符的void指针,因为new,placement new等总是返回一个void指针。缺点应该是显而易见的:丢失有关指向的对象的类型信息。首先,C ++缺乏反思或任何询问对象的方法。您必须将类型信息保留在脑中并使用来回进行实际使用。由于没有类型安全的方法来从无效指针进行强制转换,因此可能会出现欢闹。
如果这是函数的返回类型:
void* foo = some_function( _arg0 );
任何使用您的代码的作者都需要弄清楚应该发生什么。不幸的是,经常会发生什么事情以及作者认为应该从函数返回的内容是非常不同的。
<强> 2。 C风格的工会
如果你想限制你自己支持的N种类型而不是java.lang.Object可以处理的无限类型,那么就有unions。这些可以在同一内存空间上保存一组预定义的值类型,只要它们是POD数据类型即可。工会缺少两个非常重要的事情:能够知道分配了哪个值以及保持非POD类型的能力。这完全排除了它们与任何具有任何功能的对象一起使用,例如std::string
。
澄清上述内容的实际含义:
union myType{
int a;
char b[4];
};
如果我在“myType”实例的“b”部分中设置第一个char,那么我也将int的第一个字节设置为相同的值。在C ++中,这些实际上只对内存破解和极低级别编程有用(想想嵌入式等)。它们不是惯用的C ++。
第3。提升::任何
现在,如果你真的想要“我可以拥有任何东西”,那么请使用Boost::Any。这可以容纳任何对象而不会破坏很多非常有用的类型信息。 Boost文件在其目的上比我更好。取自Any:
的介绍部分有时需要通用(在一般意义上而不是基于模板的编程)类型:变量是真正可变的,适应许多其他更具体类型的值而不是C ++的普通严格和静态类型。
想想任何解决与void指针相关的许多问题,例如丢失有关所包含对象的信息以及安全地转换为正确类型的能力。
<强> 4。升压::变体强>
Boost::Variant在不丢失对象信息的情况下解决了与union类型相同的问题。此外,它可以与非POD类型的对象一起使用。正如文档所说的那样:
典型的解决方案以对象的动态分配为特色,随后通过公共基类型(通常是虚基类Hen01或更危险的是,* *)进行操作。然后可以通过多态向下构造(例如,dynamic_cast,boost :: any_cast等)来检索具体类型的对象。
但是,由于以下原因,此类解决方案极易出错:
- 在编译时无法检测到转发错误。因此,不正确使用向下转换结构将导致仅在运行时检测到错误。
- 可以忽略添加新的混凝土类型。如果将新的具体类型添加到层次结构中,则现有的向下转码将继续按原样工作,完全忽略新类型。因此,程序员必须在多个位置手动定位和修改代码,这通常会导致难以找到的运行时错误。
醇>
编辑:
重新组织以显示我在回答OP时的想法和原因。我也在下面发表评论。
答案 1 :(得分:10)
没有 direct 等同于java.lang.Object x = new Foo()
,因为在C ++中,并非一切都是对象。但取决于您希望如何使用这些Object
,您可以实现相同的目标。
C ++中与java.lang.Object x = new Foo()
最接近的等价物是使用Abstract Base Classes
(ABC
)。 ABC是一个被设计为其他类的基类的类。您通过为您的班级至少提供一个pure virtual member function来创建ABC,并使用以下语法指定:
class Object
{
public:
virtual int my_func() = 0; // The "= 0" means "pure virtual"
};
Pure Virtual成员函数通常在基类中没有实现(参见脚注* 1)。无法创建ABC的实例:
int main()
{
Object obj; // not possible because Object is an ABC
}
为了使用ABC,您必须创建它的子类并在派生类中实现每个纯虚拟成员函数:
class Foo : public Object
{
public:
int my_func() { return 42; } // use of "virtual" is assumed here
};
现在,您可以创建Foo
的实例,同时获取指向基类的指针:
int main()
{
Object* my_obj = new Foo;
}
通常的免责声明在上面的代码中适用于使用智能指针等。为清楚起见,我省略了这一点,但从现在开始,我将使用shared_ptr
。
您还可以获得对Object
的{{1}}引用,而不必担心slicing
Foo
关于析构函数和ABCs的重要说明。实现ABC时,经常需要在基类中使用虚拟析构函数(脚注* 2)。如果您没有在基类中实现虚拟析构函数,那么当您尝试通过基类指针int main()
{
Foo my_foo;
Object& obj_ref = my_foo; // OK
}
对象时,您将evoke undefined behavior,这很糟糕。
delete
事实上,在我实现ABCs的实际经验中,我经常发现我真正想成为纯虚拟的唯一成员函数是析构函数。我设计的ABCs通常有许多不纯的虚拟方法,然后是一个虚拟析构函数。 IMO(有争议的),这是设计ABC时的一个很好的起点:使dtor保持纯净,并在基类中保留最少数量的非纯虚拟成员函数,并为基础中的纯虚拟dtor提供实现类。当你以这种方式设计时,你会发现在实际代码中你无法做到的事情,那就是你偏离这种设计的时候。
<强>脚注:强>
* 1)基类可以为基类中的纯虚拟成员函数提供定义。但这不是常态,你可能会这样做的原因有些超出了这篇文章的范围。请注意,当您执行此操作时,标准中有一条特殊规则,即您可能不会在声明中提供定义;他们必须分开。像这样:
class Object
{
public:
virtual int my_func() = 0;
};
class Foo : public Object
{
public:
int my_func() { return 42; }
};
int main()
{
Object* obj = new Foo;
delete obj; // Undefined Behavior: Object has no virtual destructor
}
* 2)关于拥有虚拟析构函数的规则有例外。超出了本文的范围,但更好的经验法则是“A base class destructor should be either public and virtual, or protected and nonvirtual”
答案 2 :(得分:4)
没有等价物,因为Java从托管堆分配对象,C ++在非托管内存中分配它们。 JVM跟踪Java中的对象,使用标记和扫描自动进行垃圾回收,而C ++则要求显式释放所有内存。
运行时环境根本不同,由于类似的语法,因此绘制类比是一个陷阱。
答案 3 :(得分:-1)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-+YQ4JLhjyBLPDQt//I+STsc9iw4uQqACwlvpslubQzn4u2UU2UFM80nGisd026JF" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
<nav class="navbar navbar-expand-xl navbar-light bg-light">
<!-- Collection of nav links, forms, and other content for toggling -->
<div id="navbarCollapse" class="collapse navbar-collapse justify-content-start">
<div class="navbar-nav ml-auto">
<div class="nav-item dropdown">
<a href="#" data-toggle="dropdown" class="nav-link dropdown-toggle user-action"> P<b class="caret"></b></a>
<div class="dropdown-menu">
<a href="#" class="dropdown-item"><i class="fa fa-user-o"></i> Profile creation</a></a>
<a href="#" class="dropdown-item"><i class="fa fa-calendar-o"></i> Calendar</a></a>
<a href="#" class="dropdown-item"><i class="fa fa-sliders"></i> Settings</a></a>
<div class="dropdown-divider"></div>
<a href="#" class="dropdown-item"><i class="material-icons"></i> Logout</a></a>
</div>
</div>
</div>
</div>
</nav>