Roc*_*net 58 c++ inheritance integer language-design strong-typing
我很想能够做到这一点:
class myInt : public int
{
};
Run Code Online (Sandbox Code Playgroud)
为什么我不能?
我为什么要这样?更强的打字.例如,我可以定义两个类intA和intB,这让我做intA + intA或intB + intB,但不是intA + intB.
"Ints不是课程." 所以呢?
"Ints没有任何会员数据." 是的,他们有,他们有32位,或其他什么.
"Ints没有任何会员功能." 好吧,他们有很多像+和的运营商-.
Jer*_*fin 82
尼尔的评论非常准确.Bjarne提到考虑并拒绝这种确切的可能性1:
初始化器语法过去对于内置类型是非法的.为了实现它,我介绍了内置类型具有构造函数和析构函数的概念.例如:
Run Code Online (Sandbox Code Playgroud)int a(1); // pre-2.1 error, now initializes a to 1我考虑扩展这个概念,允许从内置类派生,并为内置类型显式声明内置运算符.但是,我克制了自己.
int与拥有int成员相比,允许从a派生实际上并没有给C++程序员带来任何新的东西.这主要是因为int没有任何虚拟函数可以覆盖派生类.更严重的是虽然,C转换规则是如此混乱是假装int,short等等,都是乖巧普通班是行不通的.它们要么是C兼容的,要么它们遵守相对良好的C++规则,但不能同时遵循两者.
就评论而言,表现不能成为一个类,它(至少大部分)都是假的.在Smalltalk中,所有类型都是类 - 但几乎所有Smalltalk实现都有优化,因此实现可以与您使非类类型工作的方式基本相同.例如,smallInteger类表示一个15位整数,并且'+'消息被硬编码到虚拟机中,因此即使您可以从smallInteger派生,它仍然提供类似于内置类型的性能(虽然Smalltalk与C++的不同之处在于,直接的性能比较很难并且不太可能意味着很多.
编辑:在C或C++中可能不需要SmallInteger的Smalltalk实现中"浪费"的那一位.Smalltalk有点像Java - 当你"定义一个对象"时,你实际上只是定义一个指向对象的指针,你必须动态分配一个对象来指向它.您操作的内容,作为参数传递给函数等,始终只是指针,而不是对象本身.
这不是 littleInteger的实现方式 - 在这种情况下,它们将整数值直接放入通常是指针的位置.为了区分smallInteger和指针,它们强制所有对象在偶数字节边界处分配,因此LSB始终是清空的.smallInteger总是设置LSB.
然而,大多数情况是必要的,因为Smalltalk是动态类型的 - 它必须能够通过查看值本身来推断出类型,而smallInteger基本上使用该LSB作为类型标记.鉴于C++是静态类型的,从来没有必要从值中推断出类型,所以你可能不需要浪费那一点.
1在C++的设计和演变中,§15.11.3.
3Da*_*ave 53
Int是序数类型,而不是类.你为什么想要?
如果需要向"int"添加功能,请考虑构建具有整数字段的聚合类,以及公开所需的任何其他功能的方法.
更新
@OP "Ints不是班级"所以?
继承,多态和封装是面向对象设计的基石.这些都不适用于序数类型.你不能从int继承,因为它只是一堆字节而且没有代码.
Int,chars和其他序数类型没有方法表,因此无法添加方法或覆盖它们,这实际上是继承的核心.
jal*_*alf 25
我为什么要这样?更强的打字.例如,我可以定义两个类intA和intB,这使我可以执行intA + intA或intB + intB,但不能执行intA + intB.
这是没有意义的.你可以在不继承任何东西的情况下做到这一切.(另一方面,我没有看到你如何使用继承来实现它.)例如,
class SpecialInt {
...
};
SpecialInt operator+ (const SpecialInt& lhs, const SpecialInt& rhs) {
...
}
Run Code Online (Sandbox Code Playgroud)
填写空白,你有一个解决问题的类型.你可以做SpecialInt + SpecialInt或int + int,但SpecialInt + int将无法编译,完全按照你想要的.
另一方面,如果我们假装继承自int是合法的,并且我们SpecialInt派生自int,那么SpecialInt + int 就会编译.继承会导致您想要避免的确切问题.不继承可以轻松避免问题.
"Ints没有任何会员功能." 好吧,他们有一大堆运营商,比如+和 - .
但这些不是成员函数.
Ste*_*eel 14
如果OP真的想要理解为什么C++就是这样的话,那么他应该得到一份Stroustup的书"C++的设计和演变".它解释了在C++早期这个以及许多其他设计决策的基本原理.
Mas*_*son 10
因为int是本机类型而不是类
编辑:将我的评论移到我的答案中.
它来自C遗产以及原始人所代表的东西.c ++中的原语只是一个字节集合,除了编译器之外几乎没有什么意义.另一方面,类有一个函数表,一旦你开始继承继承和虚拟继承路径,那么你就有了一个vtable.这些都不存在于原语中,并且通过使它呈现你会a)打破许多假定int只有8个字节的c代码和b)使程序占用更多的内存.
以另一种方式思考.int/float/char没有任何数据成员或方法.把这些原语想象成夸克 - 它们是你无法细分的构建块,你用它们来制造更大的东西(道歉,如果我的类比稍微偏离,我不知道足够的粒子物理)
Scott Meyer(Effective c ++有一个非常有效和强大的解决方案来解决你在c ++中强类型基类型的问题,它的工作原理如下:
强类型是一个可以在编译时解决和评估的问题,这意味着您可以在部署的应用程序中在运行时使用多种类型的序数(弱类型),并使用特殊的编译阶段来消除不适当的类型组合在编译时.
#ifdef STRONG_TYPE_COMPILE
typedef time Time
typedef distance Distance
typedef velocity Velocity
#else
typedef time float
typedef distance float
typedef velocity float
#endif
Run Code Online (Sandbox Code Playgroud)
然后,您可以定义Time,Mass,Distance与过载到适当的操作所有(唯一的)合适的运营商是类.在伪代码中:
class Time {
public:
float value;
Time operator +(Time b) {self.value + b.value;}
Time operator -(Time b) {self.value - b.value;}
// don't define Time*Time, Time/Time etc.
Time operator *(float b) {self.value * b;}
Time operator /(float b) {self.value / b;}
}
class Distance {
public:
float value;
Distance operator +(Distance b) {self.value + b.value;}
// also -, but not * or /
Velocity operator /(Time b) {Velocity( self.value / b.value )}
}
class Velocity {
public:
float value;
// appropriate operators
Velocity(float a) : value(a) {}
}
Run Code Online (Sandbox Code Playgroud)
完成此操作后,编译器将告诉您违反上述类中编码规则的任何地方.
我会让你自己解决剩下的细节,或者买这本书.
别人说的是真的...... int在C++中是一个原始的(很像C#).但是,你可以通过构建一个类来实现你想要的int:
class MyInt
{
private:
int mInt;
public:
explicit MyInt(int in) { mInt = in; }
// Getters/setters etc
};
Run Code Online (Sandbox Code Playgroud)
然后,您可以继承您所需要的一切.
没有人提到 C++ 被设计为(主要)与 C 向后兼容,以便简化 C 编码器的升级路径,因此struct默认为所有成员 public 等。
拥有int一个您可以覆盖的基类将从根本上使该规则复杂化,并使编译器实现变得地狱般,如果您希望现有的编码人员和编译器供应商支持您的新兴语言,则可能不值得付出努力。
| 归档时间: |
|
| 查看次数: |
19458 次 |
| 最近记录: |