- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
所以我正在刷新 C++,老实说,它已经有一段时间了。我制作了一个控制台乒乓球游戏作为一种复习任务,并获得了一些关于对我的类使用多态性以派生自基本“GameObject”(具有一些将对象绘制到屏幕的基本方法)的输入。
其中一个输入是(我随后询问过)从基类派生时内存是如何工作的。因为我并没有真正做过很多高级 C++。
例如,假设我们有一个基类,现在它只有一个“绘制”方法(顺便说一句,为什么我们需要为它说 virtual
?),因为所有其他派生对象实际上只共享一个公共(public)方法, 正在绘制:
class GameObject
{
public:
virtual void Draw( ) = 0;
};
例如我们还有一个球类:
class Ball : public GameObject
我收到的信息是,在适当的游戏中,这些可能会保存在某种游戏对象指针 vector 中。像这样:std::vector<GameObject*> _gameObjects;
(所以是指向游戏对象的指针 vector )(顺便说一句,为什么我们要在这里使用指针?为什么不只是纯游戏对象?)。我们将使用以下内容实例化这些游戏对象之一:
_gameObjects.push_back( new Ball( -1, 1, boardWidth / 2, boardHeight / 2 ); );
(new
返回指向对象的指针是否正确?IIRC)。根据我的理解,如果我尝试做类似的事情:
Ball b;
GameObject g = b;
事情会变得一团糟(如此处所示:What is object slicing?)
但是...当我执行 new Ball( -1, 1, boardWidth / 2, boardHeight / 2 );
时,我不是简单地自己创建 Derived 对象吗?还是自动将其分配为游戏对象?我无法真正弄清楚为什么一个有效而另一个无效。它与通过 new
创建对象有关吗?对比 Ball ball
例如?
如果这个问题没有意义,我很抱歉,我只是想了解这个对象切片是如何发生的。
最佳答案
基本问题是复制对象(这在类是“引用类型”的语言中不是问题,但在 C++ 中默认是按值传递事物,即制作拷贝)。 “切片”是指将较大对象(B
类型,派生自 A
)的值复制到较小对象(A
类型)中).因为 A
较小,所以只制作了部分拷贝。
当你创建一个容器时,它的元素是它们自己的完整对象。例如:
std::vector<int> v(3); // define a vector of 3 integers
int i = 42;
v[0] = i; // copy 42 into v[0]
v[0]
是一个 int
变量,就像 i
一样。
类也会发生同样的事情:
class Base { ... };
std::vector<Base> v(3); // instantiates 3 Base objects
Base x(42);
v[0] = x;
最后一行将 x
对象的内容复制到 v[0]
对象中。
如果我们像这样改变 x
的类型:
class Derived : public Base { ... };
std::vector<Base> v(3);
Derived x(42, "hello");
v[0] = x;
... 然后 v[0] = x
尝试将 Derived
对象的内容复制到 Base
对象中。在这种情况下发生的是所有在 Derived
中声明的成员都被忽略。仅复制在基类 Base
中声明的数据成员,因为这是所有 v[0]
的空间。
指针给你的是避免复制的能力。当你做的时候
T x;
T *ptr = &x;
,ptr
不是x
的拷贝,它只是指向x
。
同样,你可以这样做
Derived obj;
Base *ptr = &obj;
&obj
和 ptr
有不同的类型(分别是 Derived *
和 Base *
),但是 C++ 允许这段代码无论如何。因为 Derived
对象包含 Base
的所有成员,所以可以让 Base
指针指向 Derived
实例。
这给你的本质上是一个简化的 obj
接口(interface)。当通过ptr
访问时,它只有在Base
中声明的方法。但是因为没有进行复制,所以所有数据(包括 Derived
特定部分)仍然存在并且可以在内部使用。
至于virtual
:通常,当你通过Base
类型的对象调用方法foo
时,它会调用恰好 Base::foo
(即在 Base
中定义的方法)。即使调用是通过一个指针进行的,该指针实际上指向派生对象(如上所述)并具有不同的方法实现,也会发生这种情况:
class Base {
public:
void foo() const { std::cout << "hello from Base::foo\n"; }
};
class Derived : public Base {
public:
void foo() const { std::cout << "hello from Derived::foo\n"; }
};
Derived obj;
Base *ptr = &obj;
obj.foo(); // calls Derived::foo
ptr->foo(); // calls Base::foo, even though ptr actually points to a Derived object
通过将 foo
标记为 virtual
,我们强制方法调用使用对象的实际类型,而不是调用所通过的指针的声明类型:
class Base {
public:
virtual void foo() const { std::cout << "hello from Base::foo\n"; }
};
class Derived : public Base {
public:
void foo() const { std::cout << "hello from Derived::foo\n"; }
};
Derived obj;
Base *ptr = &obj;
obj.foo(); // calls Derived::foo
ptr->foo(); // also calls Derived::foo
virtual
对普通对象没有影响,因为声明类型和实际类型始终相同。它只会影响通过指向对象的指针(和引用)进行的方法调用,因为它们能够引用其他对象(可能不同类型)。
这是存储指针集合的另一个原因:当您有几个不同的 GameObject
子类时,它们都实现了自己的自定义 draw
方法,您需要注意对象的实际类型的代码,因此在每种情况下都会调用正确的方法。如果 draw
不是虚拟的,您的代码将尝试调用不存在的 GameObject::draw
。根据您对其编码的精确程度,这要么不会首先编译,要么在运行时中止。
关于c++ - 避免对象切片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56464702/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!