C++编程思想学习笔记

来源:互联网 发布:mac口红价位 编辑:程序博客网 时间:2024/05/18 03:46

1。声明与定义:声明是向编译器介绍名字---标识符。而定义为名字分配存储空间。 定义也可以是声明。如果定义int x;之前,编译器没有发现标识符x,编译器则把这一标识符看成是声明并立即为它分配存储空间。我们常用的写法,int i;就属于这种"定义是声明的"情况,纯粹的变量声明应该使用extern关键字。函数声明extern可以省略,因为编译器可以通过函数名后面跟的是;还是{来判断是声明还是定义。

2。名字空间是十分方便和有用的工具,但名字空间的出现意味着在写程序之前,必须知道它们。如果只是简单的包含头文件,使用头文件中的一些函数或对象,编译时,可能会遇到一些奇怪的错误,确切地说,如果仅仅只包含头文件,编译器无法找到任何有关函数和对象的声明。在多次看到编译器的这种提示后,我们会熟悉他所代表的含义(即:虽然包含了头文件,但所有的声明应该都在一个名字空间中,而没有告诉编译器我们想要用哪个名字空间)

3。函数,局部变量,全局变量存储地址

#include <iostream>

using namespace std;

int dog, cat, bird, fish;

void f(int pet){
     cout << "pet id number: " << pet << endl;
}

int main(int argc, char *argv[]){
    int i, j, k;
    cout << "f(): " << (long)&f << endl;
    cout << "dog: " << (long)&dog << endl;
    cout << "cat: " << (long)&cat << endl;
    cout << "bird: " << (long)&bird << endl;
    cout << "fish: " << (long)&fish << endl;
    cout << "i: " << (long)&i << endl;
    cout << "j: " << (long)&j << endl;
    cout << "k: " << (long)&k << endl;
   
    system("PAUSE");
    return EXIT_SUCCESS;
}

f(): 4199312
dog: 4468752
cat: 4468756
bird: 4468760
fish: 4468764
i: 2293620
j: 2293616
k: 2293612

4。局部变量经常被称为自动变量(automatic variable),因为他们在进入作用域时自动生成,离开作用域时自动消失。关键字auto可以显式的说明这个问题,但是局部变量默认为auto,所以没有必要声明为auto。

5。当想给一个函数传递数组时,如果声明一个数组为函数参数,实际上真正声明的是一个指针,也就是说数组不可以按值传递,也就是<高质量C/C++编程指南>里面说的,当数组作为一个函数参数时,自动退化为一个指针,使用sizeof计算出来的是指针的大小,而不是数组的大小。

6。在一个预处理器宏中的参数前面是用一个#,预处理器会把这个参数转换为一个字符数组。

#include <iostream>

using namespace std;

#define PR(A) cout << #A << ": " << (A) << endl;

int main() {
    int a = 1, b = 2, c = 3;
    PR(a); PR(b); PR(c);
    PR(a + b);
    P((c - a)/b);
 
    system("PAUSE");
    return EXIT_SUCCESS;

}

7。struct B { void f();};

sizeof(B) = 1;//dev cpp

struct B是奇异的,因为它是没有数据成员的struct。在C中,这是不合法的,但在C++中,以这种选择方式创建一个struct,唯一的目的就是划定函数名的范围,所以这是允许的。在该语言较早的版本中,这个长度是零,但是,当创建这样的对象时出现了笨拙的情况:他们与紧跟着他们创建的对象有相同的地址,没有区别。对象的基本规则之一就是每个对象必须有一个唯一的地址,因此,无数据成员的结构总应当有最小的非零长度。

8。下面是一个带构造函数的类的简单例子:

class X {

  int i;

public:

  X(); // Constructor

};

现在当一个对象被定义时:

void f() {

  X a;

}

这时就好像是a是一个int一样:为这个对象分配内存。但是当程序执行到a的时候,构造含数字东北调用,因为编译器已悄悄地在a的定义处插入了一个X::X()的调用。就像其他成员函数被调用一样。传递到构造函数的第一个(秘密)参数是this指针,也就是调用这一函数的对象的地址,不过,对构造函数来说,this指针指向一个没有被初始化的内存块,构造函数的作用就是正确的初始化该内存块。

9。默认构造函数就是不带任何参数的构造函数。
当且仅当在一个结构或类中没有构造函数时,编译器会自动为它创建一个。
一旦有构造函数,编译器便不再提供不带任何参数的默认构造函数,此时需要显式的编写默认的构造函数。
class Test {
public:
  Test(int i);
};

Test::Test(int ii) {//有构造函数,编译器便不再提供不带任何参数的默认构造函数
  i = ii;
}

int main(int argc, char *argv[])
{
    //Test t; // Error: no matching function for call to Test::Test()'
    //提示找不到不带任何参数的构造函数,因为有构造函数
    //编译器不再提供不带任何参数的默认构造函数,需要显式的编写默认的构造函数
}

10。没有类型名和标识符的联合(union)叫匿名联合(anonymous union),我们访问一个匿名联合的成员就向访问普通的变量一样。唯一的区别就是所有的变量共用同一内存空间
int main() {
  union {
    int i;
    float f;
  }
  // Access members without using qualifiers:
  i = 12;
  f = 1.22;
}

11。const成员函数
首先,注意前面带const的函数声明,它表示函数的返回值是const,必须把修饰符const放在函数参数表的后面,例如
//: ConstMember.cpp
class X {
  int i;
public:
  X(int ii);
  int f() const;//关键字const表明它是一个const成员函数
};

X::X(int ii) :i(ii) {}
int X::f() const { return i;} // 关键字const必须用同样的方式重复出现在定义里,否则编译器把它看成一个不同的函数

//一个const成员函数调用const和非const对象是安全的,因此可以把它看作成员函数的最一般形式。不修改数据成员的任何函数都//应该把他们声明为const,这样它可以和cons对象一起使用。

12。在const成员函数内部改变数据成员的两种方法
第一种:取this并把它强制转换成指向当前类型对象的指针。看来this已经是所需的指针,但是,在const成员函数内部,它实际上是一个const指针,所以,还应把它强制转换成一个普通指针,这样就可以在那个运算中去掉常量性。
// Castaway.cpp
class Y {
  int i;
public:
  Y();
  void f() const;
};

Y::Y() { i = 0; }
void Y::f() const {
  //! i++; // Error -- constt member function
  ((Y*)this)->i++; // OK: cast away const-ness
  // Better: use C++ explicit cast syntax:
  (const_cast<Y*>(this))->i++;
}
            
int main(int argc, char *argv[])
{
    const Y yy;
    yy.f();
   
    system("PAUSE");
    return EXIT_SUCCESS;
}

第二种方法:使用关键字mutable,以指定一个特定的数据成员可以在一个const对象里被改变。
//Mutable.cpp
class Z {
  int i;
  mutable int j;
public:
  Z();
  void f() const;
}; // 类声明之后,一定要记得加";",这次又忘加了,看了老半天才看出来

Z::Z() : i(0), j(0) {}

void Z::f() const {
  //! i++; // Error -- const member function;
  j++; // OK: mutable
  cout << j << endl;
}

int main(int argc, char *argv[])
{
    const Z zz;
    zz.f(); // Actually changes it!
   
    system("PAUSE");
    return EXIT_SUCCESS;
}
13。内联函数
#include <cstdlib>
#include <iostream>

using namespace std;

class Forward {
  int i;
public:
  Forward() : i(0) {}
  // Call to undeclared function:
  int f() const { return g() + 1; } // 函数f()调用g(),但此时还没有声明g()。这也能正常工作,因为C++语言规定:只有在类声明结束后,其中的内联函数才会被计算。
  int g() const { return i; }
};

int main(int argc, char *argv[])
{
    Forward frwd;
    frwd.f();
   
    system("PAUSE");
    return EXIT_SUCCESS;
}

14。静态数据成员
#include <cstdlib>
#include <iostream>

using namespace std;

class Egg {
  static Egg e;
  int i;
  Egg(int ii) : i(ii) {}
  Egg(const Egg&); // Prevent copy-construction
public:
  static Egg* instance() { return &e; }
  int val() const { return i; }
};

Egg Egg::e(47);

int main(int argc, char *argv[])
{
    cout << Egg::instance()->val() << endl;
   
    system("PAUSE");
    return EXIT_SUCCESS;
}

将拷贝构造函数设为私有,以完全防止创建其他对象,如果没有他,就能通过下面那样创建一个Egg对象。
Egg e = *Egg::instance();
Egg e2(*Egg::instance());
这两条语句都使用了拷贝构造函数。

原创粉丝点击