C++ C++;标准

C++ C++;标准,c++,C++,我决定更加熟悉我最喜欢的编程语言,但仅仅阅读标准是无聊的 什么是最令人惊讶的、反直觉的或只是普通的奇怪的C++元素?是什么让你震惊到跑到离你最近的编译器那里去检查它是否真的是真的 我会接受第一个答案,即使在我测试后我也不会相信 几个声明器的顺序实际上是无序的: volatile long int const long extern unsigned x; 与 extern const volatile unsigned long long int x; 考虑到C++是多么的不可原谅,我发现标

我决定更加熟悉我最喜欢的编程语言,但仅仅阅读标准是无聊的

什么是最令人惊讶的、反直觉的或只是普通的奇怪的C++元素?是什么让你震惊到跑到离你最近的编译器那里去检查它是否真的是真的


我会接受第一个答案,即使在我测试后我也不会相信

几个声明器的顺序实际上是无序的:

volatile long int const long extern unsigned x;

extern const volatile unsigned long long int x;

考虑到C++是多么的不可原谅,我发现标准确实允许你去<代码>删除< /Cultnull指针>。例如:

void dosomething() throw()
{
   // ....
}

void doSomethingElse() throw(std::exception)
{
  // ....
}

直观地说,这似乎是与编译器的约定,表明此函数不允许抛出除所列异常以外的任何异常。但实际上,这在编译时没有任何作用。相反,它是一种运行时机制,不会阻止函数实际抛出异常。更糟糕的是,如果抛出未列出的异常,它将通过调用
std::terminate()

来终止应用程序。不太清楚数组启动器是否会像枚举定义中那样跳入索引

// initializing an array of int
int a[ 7] = { [5]=1, [2]=3, 2};
// resulting in
int a[ 7] = { 0, 0, 3, 2, 0, 1, 0};

// initializing an array of struct
struct { int x,y; } ar[ 4] = { [1].x=23, [3].y=34, [1].y=-1, [1].x=12};
// resulting in
struct { int x,y; } ar[ 4] = { { 0, 0}, { 12, -1}, { 0, 0}, { 0, 34}};

// interesting usage
char forbidden[ 256] = { ['a']=1, ['e']=1, ['i']=1, ['o']=1, ['u']=1};

大多数都是C++的。

我发现

有点令人惊讶。
class aclass
{
public:
int a;
};

some_function(aclass());
将在
某些功能中将
a
初始化为
0
,而

aclass ac;
some_function(ac);
将使它统一起来。 如果明确定义
aclass
的默认构造函数:

class aclass
{
public:
aclass(): a() {}
int a;
};
然后
aclass-ac

也会将
a
初始化为
0

对象在构造期间更改类型。

特别是,当从构造函数调用虚拟函数时,您将不会调用最派生的重写。而是从当前正在构造的类调用实现。如果该实现恰好是
0
(纯虚拟函数),则程序将在运行时崩溃

一个半真实世界的例子:

class AbstractBase {
  public:
    AbstractBase() {
      log << "Creating " << className() << endl;
    }
  protected:
    virtual string className() const = 0;
}

class ConcreteGuy {
  protected:
    virtual string className() const { return "ConcreteGuy"; }
}
类抽象库{
公众:
AbstractBase(){

C++语句中的log 评估为某事…

int main()
{
    "This is a valid C++ program!"
    "I will list the first five primes:";
    2;
    3;
    5;
    7;
    11;
}


应该是社区维基。另请参阅,谢谢。我没有想到搜索“隐藏功能”.Herb Sutter非常详细地解释了为什么您永远不应该编写异常规范:这正是我们使用注释掉的throw语句的原因,仅用于文档目的…非常遗憾:/-1,这是一个gcc扩展。问题提到了上述代码段格式不正确的标准。是的,这是特定于gcc的。如aw所述虽然gcc很简单,但它不是标准的一部分。这真的很令人惊讶吗?想解释一下为什么你会感到惊讶吗?我不知道你可以将“long-long-int”部分分开。实际上,像“extern”这样的存储说明符是非法的出现在类型说明符内。它们必须出现在之前或之后。第一个例子不是有效的C++,但是如果你交换了“Extn”和“unSube”。@ SMOMOTY:仅基于形式语法规则,你是正确的。但是,7.1.1.2(DCL,type,Simple)点3个状态。“当允许使用多个简单类型说明符时,它们可以以任何顺序与其他decl说明符自由混合。”这是从这里的C++0x草案中得出的(不确定其他标准):当您构造一个ConcreteGuy(假设它是从AbstractBase派生的)时,这并不奇怪由于基类是先构造的,所以在构造函数完成之前,它没有一个ConcreteGuy类可调用。我同意这是有道理的。但当我第一次遇到这个问题时,它仍然引起了相当多的标题冲突。特别是因为Java和C#的行为不同,允许您对未完全构造的对象调用方法。@gbjbaanb(多好的名字啊!):不太可能,编译器会将构造调用与大多数派生类型构造函数相匹配,并开始执行该构造函数。现在,执行顺序首先是初始化列表,然后是构造函数体,标准声明初始化开始执行当前类的第一个基类。算法意味着完全构造的第一个类型(初始化列表和构造函数主体都是竞争的)是派生较少的类型(根据它的某些定义)……事实上,编译器事先知道最派生对象的确切类型。虚拟表按其初始化顺序初始化的事实是一个设计问题。Java和C#都采用了不同的方法,虽然它们也将从基类型一直构造到最派生的类型,但虚拟方法表(或同等机构)在调用基本构造函数之前,已经完全构造了最派生类型的方法。另一方面,这是另一个问题的一个问题,因为可以在一个尚未构建的层次结构上调用一个虚拟方法。我发现C++中有多少人不知道可以删除空指针。C在移动到C++之前,我学会了不做任何空指针。C++定义了一个“NOP”,用于“代码>删除null;”可能是有用的,但它也可以隐藏错误。如果你在C代码>自由(NULL)中意识到,就不会惊讶。
定义得很好。什么?想解释一下它的区别吗?它是否初始化为调用而推送的堆栈空间?使用
aclass()
由于参数使编译器填写默认构造函数,将所有内容初始化为默认值。但是,当您仅声明一个变量时,除非您自己定义了默认构造函数,否则不会调用任何构造函数。嗯,这是真的,我尝试了:P.+1用于我不知道的内容。如果没有return语句,它不是有效的程序事实上,在C++中,<>代码>主体< /C>不需要明确返回一个值。