模板参数=void*的编译器错误 - 页 6

 
Alexey Navoykov:

一切工作都很正常,你为什么要编造这个?

在日志中我们得到。

void A::~A()
void B::~B()

我为什么要上当呢......。

那么我很抱歉,不知道你可以这样做,MKL没有多少C++。从好的方面看,删除void*是UB。

 

关于交易、自动交易系统和交易策略测试的论坛

新版MetaTrader 5 build 1930:MQL5中的浮动图表窗口和.Net库

Alexey Navoykov, 2018.12.15 02:44

亲爱的开发者们。在早些时候的一个主题中,我们讨论了允许基类向派生类隐式铸造的编译器缺陷,但它似乎没有被你注意到。 这是一个严重的问题,使错误检查变得困难,并且在积极使用OOP 时成为一个持续的头痛问题。 这样的铸造应该只有显式。 这是C++和C#的一般规则。

class A {  };

class B : public A { };

A* a = new A;

B* b = a;  // Нет ошибки компиляции!

void f(B*) {  }

void OnInit()
{ 
  f(a);  // Нет ошибки компиляции!
}  

那么在这里该怎么做呢?

class A {  };

class B : public A { };

A* a = new A;

void* v = a;

B* b = v;  // Нет ошибки компиляции!


这种行为是否也应该被认为是一种错误?

 
Alexey Navoykov:

如果样式器使代码难以阅读,那么到底为什么要使用它呢?

对我来说,只有当一个造型器的所有规则都可以灵活地定制时,它才是好的。

因此,如果你在打印机打印的形式下(或在论坛上,如这里)阅读别人的代码。

 
fxsaber:
关于括号
((A*)(b.GetPtr())).f(); // Доп. скобки, чтобы подчеркнуть, что именно имелось в виду, не полагаясь на приоритеты.

好吧,也许它能强调你,但对我来说,它只会让人困惑。 但看这个表达式,我不能立即理解这里调用的是谁的方法。 但在前面两行中,它一下子就清楚了。

要了解正在做的事情,你应该打开所有的括号。 括号越多,浪费在弄清事情上的时间就越多,特别是如果它们没有用空格隔开。

 
Alexey Navoykov:

好吧,也许它能强调你,但对我来说,它只会让人困惑。 但看着这个表达式,我无法立即理解这里调用的是谁的方法。 但在前面两行,一切都一下子清楚了。

要了解到底在做什么,你必须打开所有的括号。 括号越多--就越要花时间了解发生了什么。 特别是如果它们没有以任何方式用空格分隔。

额外的括号不是用来阅读的--让文体学家 来处理,放上空格。

但对于写作时 的自制力。为什么我在敏感领域写作时要依赖别人的优先权,同时要知道我在写跨平台代码(不一定只有MT4/5),可以移植到其他语言?额外的括号完全消除了语言优先权的影响。一切都变得绝对不含糊。正因为如此,有一个100%的可靠性,即在下一次建造之后,这个地方不会有任何故障。


此外,当我读到这个托架地狱时,我必须花时间来绝对理解我在这里的确切含义。而关于能见度的问题。

bool a = (1 < 2) && (3 < 4);
bool b = 1 < 2 && 3 < 4;

让我们问一下,哪种方案更直观?

 
fxsaber:

这种行为是否也算作一种错误?

当然是这样。这是同一件事。

因此,事实证明,在真正可能出现问题的地方,什么都不会产生,至少需要警告(甚至是编译错误)。 但是,当括号强加给我们时,他们不放过任何警告),这里有些人甚至提议禁止没有括号的编译,并以抽头威胁我们)这就是我们的生活......

 
Alexey Navoykov:

当然了。这是同一件事。

所以事实证明,如果真的有问题,而且至少需要一个警告(甚至是一个编译错误),那么什么都不会显示。 但是有了括号,他们就不会放过任何警告),这里有些人甚至提议禁止没有括号的编译,并威胁要抽打你)这就是我们的生活......

所以你也需要一个警告?这是什么双重标准:在这两个地方的行为都是毫不含糊的,但在括号里你是反对警告的,而在这里你是支持的?

你需要一个警告,这样你就不会犯难以发现的错误。因此,难度是一个主观的评估。因此,有了括号,你就不会犯错,而在这里你可以。而对我来说,反之亦然。

那么,我们中的哪一位应该调整发布警告的规则?

 
Ilya Malev:

我不知道StringConcatenate,很遗憾在MT5中它被重新设计了,没有字符串s就不能使用。而StringFormat在4上要快得多。

一般来说,由于某些原因,这种通过字符串 "轮询 "指针的操作在5中几乎慢了一倍,尽管一般来说它在5中工作得更快,有时甚至快了一个数量级。

有可能StringConcatenate()是32位的,你不知道,开发者已经写了5和4中的metaetiters是一样的,也许是因为兼容性,他们 "包装 "了它。

昨天我试着用dynamic_cast< >来解决你的问题。 问题是MQL不允许解除对指针的定义。类方法中的函数可以通过dynamic_cast<C_myclass >( func( ))来调用,你可以通过dynamic_cast< >获得一个指向类的指针,但是如何处理一个指针呢?- 你可以重新赋值 void *ptr ,但是没有意义,因为无论如何指针不能被取消引用。

 
pavlick_:

如果你想废除CArayObject,你必须在基类上做一个覆盖(比如这个https://www.mql5.com/ru/forum/170952/page110#comment_9894796),并把它们放在一个数组中(可能是你的),但这样你就不再需要void*了。

我不反对无效*,它是需要的,但以不同的身份。

我不明白引用代码的意义(尽管我也不使用标准库)。如果将一个对象放入数组中涉及到创建它的副本,那么赋值方法或复制构造函数必须在该类中明确声明和描述,否则无论如何都没有包装器的帮助。如果你只需要把一个对象的引用放到数组中,你根本不需要任何包装器(为什么?)

顺便说一下,你似乎不知道,在mql中,if(p)delete p与 "如果引用指向一个现有的动态对象,则删除它 "并不完全相同。

class A{};

void OnStart()
 {
  A *a=new A;
  if(a) Print("Кукареку!");
  if(CheckPointer(a)==POINTER_DYNAMIC) Print("Динамический объект существует и может быть удален");
  else                                 Print("Объект не существует, либо он автоматический");
  delete a;
  if(a) Print("Кукареку!");
  if(CheckPointer(a)==POINTER_DYNAMIC) Print("Динамический объект существует и может быть удален");
  else                                 Print("Объект не существует, либо он автоматический");
 }
 
fxsaber:

而关于能见度的问题。

我们来问问,哪一个更清楚?

好吧,如果风格化程序 是这样为你格式化的

1 < 2 && 3 < 4;

那么,同样,这取决于造型师。我绝不会在我的代码中这样做。 我会这样做。

1<2 && 3<4
либо
1 < 2  &&  3 < 4