C++中是否有一个标准的“int类”?

9

是否有c ++的(至少更多或更少的)标准int类?

如果没有,C++13计划如何,并且如果不是这样,是否存在任何特殊原因?

OOP设计可能会从中受益,例如,在自定义类中具有返回int的赋值运算符将是很好的:

int i=myclass;

而不是

int i=myclass.getInt();

好的,有很多例子可以展示它的实用性,如果还没有的话,为什么不开发出来呢?

这是为了进行死推算和其他滞后补偿方案而设计的,将这些值视为“正常”的变量将会很好,希望如此!


17
没有计划,原因是C++不是一种将所有内容都塞进对象的确定性语言。 - Xeo
如果有很多例子,我想阅读一些。另外:你想在你的例子中实现什么机制?第一个比第二个更好,只是因为它更短吗?我认为第二个比第一个更好地展示了它的目的。 - Nobody moving away from SE
8
普通的 int 有什么问题? - Konrad Rudolph
3
您需要什么样的功能,int 无法提供? - tenfour
2
@eda 一个int变量是一个对象,但42不是一个对象。 - fredoverflow
显示剩余11条评论
11个回答

20

在自定义类中添加一个返回int的赋值运算符会很有用。

您可以使用转换运算符来实现:

class myclass {
    int i;
public:
    myclass() : i(42) {}

    // Allows implicit conversion to "int".
    operator int() {return i;}
};

myclass m;
int i = m;

通常情况下应该避免这样做,因为额外的隐式转换可能会引入歧义,或隐藏类型系统本应捕捉到的类别错误。在C++11中,您可以通过声明操作符explicit来防止隐式转换;然后可以使用该类来初始化目标类型,但不会被隐式转换:

int i(m);    // OK, explicit conversion
i = m;       // Error, implicit conversion

6
当你想要使用转换运算符时,必须三思而后行,因为它们会使你的代码变得不那么明显。 - Alecs
2
@Alecs:发帖者至少要三思而后行,为什么需要这样的“语义”。 - Xeo
我认为我有一个有效的使用案例需要这个行为。我希望有一个int的包装类,可以通过JNI通知Java对象其值的任何更改。通过使用转换运算符,我能够重载赋值/修改运算符(=,++,--)以通知Java对象,而不破坏现有引用对象作为整数的功能。由于无法扩展int,因为它是一种基本数据类型而不是类,因此这似乎是一个很好的解决方案。我是否遗漏了什么,或者这是我的问题的好解决方案? - StockB

6

如果你想让你的类隐式转换为 int,你可以使用一个隐式转换运算符 (operator int()),但一般来说,隐式转换会引起更多的问题和调试,而不是解决使用上的便利。


3
C++11中有显式转换。 - Puppy
虽然你总是可以用方法来模拟它们。 - Mark B

3
如果你的类模拟了一个 int,那么其他答案中提出的转换运算符解决方案就可以了。但是,你的myclass模型是什么呢?从中获取一个整数意味着什么?这是你需要考虑的问题,然后你应该得出结论:在没有任何信息的情况下获得整数很可能没有意义。 以std::vector<T>::size()为例,它返回一个整数。难道std::vector<T>应该因此可转换为整数吗?我不这样认为。方法应该被称为getInt()吗?同样,我也不这样认为。从一个名字中,你只知道它返回一个整数,无法了解它返回的具体内容。此外,它并不是唯一返回整数的方法,还有capacity()

2

为你的类实现operator int ()运算符


1

这可以通过使用强制类型转换运算符来实现。例如:

class MyClass {
private:
    int someint;
public:
    operator const int() {
        return this->someint;
    }
}

1

不会有的,也不需要。你想要做的可以通过转换运算符来实现:

#include <iostream>

struct foo {
    int x;
    foo(int x) : x(x) {}
    operator int() { return x; }
};

int main() {
    foo x(42);
    int y(x);
    std::cout << y;
}

@sbi:这取决于情况。如果你正在编写一个用于限制整数范围的类型,那么隐式转换为int就是正确的做法。当然,你很少会这样做。 - celtschk
@celtschk:我曾经也这样想过。但是我被这个问题咬了很多次。我写的为数不多的一些隐式转换,它们是代码库的一部分,而且仍在使用中,但随着时间的推移,它们都被删除了,因为它们引起了麻烦。 - sbi
@sbi:也许你遇到了不合适的隐式转换问题(请注意,C++中许多标准隐式转换在我看来是错误的)。特别要注意的是,我的示例是一个受限制的整数类,这是很少有人敢实现的(只使用整数会简单得多)。从“bigint”扩展整数类到int的隐式转换显然是错误的。 - celtschk
@celtschk:如果那些是不合适的(在我看来肯定是,因为我们不得不将它们删除),那么在我近20年的C++编程经验中,我从未遇到过隐式转换是合适的情况。我见过的所有情况,迟早都被发现是一些非常难以诊断的错误的罪魁祸首,这些错误是由隐式转换隐式启动引起的。(顺便说一句,这包括一个“Byte”类。) - sbi
是从 Byteint 的隐式转换(在我看来是适当的),还是从 intByte 的转换(在我看来是不合适的)导致了问题? - celtschk

1
不会有的,而且可能永远都不会有。
int i=myclass;

这可以通过转换运算符来实现:
struct MyClass {
    operator int() {
        return v;
    }
    int v;
} myclass = {2};
int i = myclass; // i = 2

并非所有东西都必须是“面向对象”的。C++提供了其他选择。


1

没有标准的 int 类。对于 BigDecimal 等类,您可以查看 是否有 C++ 版本的 Java 的 BigDecimal?

至于 int,如果您真的需要它,可以自己创建一个。我从未遇到过需要 Integer 类的情况。


1

有明显的理由为int创建一个类,因为int本身不允许没有任何值的存在。例如,考虑一个JSON消息。它可以包含一个名为“foo”的对象的定义,以及一个名为“bar”的整数:

{"foo": {"bar": 0}}

这意味着“bar”等于0(零),但如果您省略“bar”,就像这样:
{"foo": {}}

现在,“bar”的意义是不存在的,这是完全不同的含义,不能仅用int表示。在过去,如果出现这种情况,一些程序员会使用单独的标志,或使用特定的整数值来表示该值未提供、未定义或不存在。但无论你如何称呼它,更好的方法是为整数定义一个类,定义其功能并使其可重复使用和一致。
另一种情况是数据库表在创建后某个时间添加了一个整数列。在添加新列之前添加的记录将返回null,表示没有值存在,而在添加新列之后添加的记录将返回一个值。您可能需要针对null值和0(零)采取不同的操作。
因此,以下是int或string类的开端。但在我们看代码之前,让我们先看看用途,因为这是您首先创建类的原因,可以让您在长期运行中更轻松。
int main(int argc, char **argv) {

    xString name;
    xInt    age;

    std::cout<< "before assignment:" << std::endl;
    std::cout<< "name is " << name << std::endl;
    std::cout<< "age is " << age << std::endl;

    // some data collection/transfer occurs
    age  = 32;
    name = "john";

    // data validation
    if (name.isNull()) {
        throw std::runtime_error("name was not supplied");
    } 

    if (age.isNull()) {
        throw std::runtime_error("age was not supplied");
    }

    // data output
    std::cout<< std::endl;
    std::cout<< "after assignment:" << std::endl;
    std::cout<< "name is " << name << std::endl;
    std::cout<< "age is " << age << std::endl;

    return 0;
}

这是程序的示例输出:
before assignment:
name is null
age is null

after assignment:
name is john
age is 32

请注意,当xInt类的实例未被赋值时,“<<”运算符会自动打印“null”,而对于名称为name的xString也是如此。您可以自行决定如何处理此情况。例如,您可能决定不打印任何内容而不是打印“null”。另外,为了简洁起见,我已经硬编码了赋值。在现实世界中,您将从文件或客户端连接中收集/解析数据,在该过程中,该过程将根据输入数据设置(或不设置)数据值。当然,这个程序实际上永远不会抛出运行时异常,但我把它们放在那里是为了让您体验如何抛出错误。因此,有人可能会说,好吧,你为什么不在数据收集过程中抛出异常呢?那么,答案是,使用扩展类变量(xInt和xString),我们可以编写一个通用的、可重用的数据收集过程,然后只需在业务逻辑中检查返回的数据,我们就可以根据所发现的情况抛出适当的错误。
好的,这里是与上述主方法相配套的类代码:
#include <iostream>
#include <string>


class xInt {
private:
    int  _value=0;
    bool _isNull=true;

public:
    xInt(){}
    xInt(int value) {
        _value=value; 
        _isNull=false;
    }

    bool isNull(){return _isNull;}
    int  value() {return _value;}
    void unset() {
        _value=0;
        _isNull=true;
    }

    friend std::ostream& operator<<(std::ostream& os, const xInt& i) {
        if (i._isNull) {
            os << "null";
        } else {
            os << i._value;
        }
        return os;
    }

    xInt& operator=(int value) {
        _value=value;
        _isNull=false;
        return *this;
    }
    operator const int() {
        return _value;
    }
};

class xString {
private:
    std::string _value;
    bool   _isNull=true;

public:
    xString(){}
    xString(int value) {
        _value=value; 
        _isNull=false;
    }

    bool   isNull() {return _isNull;}
    std::string value()  {return _value;}
    void   unset()  {
        _value.clear();
        _isNull=true;
    }


    friend std::ostream& operator<<(std::ostream& os, const xString& str) {
        if (str._isNull) {
            os << "null";
        } else {
            os << str._value;
        }
        return os;
    }

    xString& operator<<(std::ostream& os) {
        os << _value;
        return *this;
    }

    xString& operator=(std::string value) {
        _value.assign(value);
        _isNull=false;
        return *this;
    }
    operator const std::string() {
        return _value;
    }
};

有些人可能会说,哇,与int或string相比,这非常丑陋,是的,我同意它非常冗长,但请记住,您只需编写基类一次,然后从那时起,您每天阅读和编写的代码看起来更像我们首先查看的主方法,非常简洁明了,对吧?接下来,您将想要学习如何构建共享库,以便将所有这些通用类和功能放入可重用的.dll或.so中,这样您只需要编译业务逻辑,而不是整个宇宙。 :)

0

没有理由需要一个,因此不会有任何的。


1
请看我的评论,针对Mike Seymour。 - StockB
看起来技术上可以(请纠正我)将 C++ 类型系统转换为仅具有对象。如果我们假装 int 是一个最终类,重载运算符并内置支持文字。因此,5 将创建类 int 的对象。为什么要这样做?嗯,如果 C++ 还添加了一些方法,例如“repeat”,则您可以编写类似于“5.repeat([]{your_code;});”的内容。难道只有一些向后兼容性问题,例如 type_traits 等吗? - sasha.sochka
现在你也可以写repeat(5, []{ your code; });。即使是C++委员会也不够疯狂,将int变成一个类。C++类型系统已经由对象(除了引用)组成。没有理由改变现有的基本类型,它们已经是对象了。 - Puppy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接