C++中类和对象的一些注意事项

1. struct和class的区别

默认的访问权限不同, struct默认访问权限是public, 而class的默认访问权限是private.

2. 构造析构函数

2.1 注意事项

  • 匿名构造函数在当前行结束后, 系统会立即释放其内存占用.
  • 不要用匿名拷贝构造函数.
  • 创建一个类之后, 编译器会自动创建三个函数, 默认构造函数, 默认析构函数, 拷贝构造函数. 如果我们提供有参构造或者拷贝构造函数, 那么编译器就不再提供默认构造.
  • 当其他类的对象作为本类成员时, 先构造其他类的对象, 再构造本类对象. 析构则是反过来.
  • 构造函数不能声明为const,因为构造函数的意义在于初始化。
  • 成员变量在使用初始化列表初始化时,与构造函数中初始化成员列表的顺序无关,只与定义成员变量的顺序有关。

2.2 限定对象只能在堆/栈上创建

2.2.1 限定对象只能在堆上创建

错误方法:

把构造函数设为私有。但是这样做,用new在堆上创建对象的时候也会调用构造函数,这样就无法在外部调用类的构造函数了。

方法1:

将析构函数设为私有,因为创建在栈上的对象是由编译器分配和释放内存空间,编译器为对象分配内存空间时,会对类的非静态函数进行检查,即编译器会检查析构函数的访问性。当析构函数设为私有时,编译器创建的对象就无法通过访问析构函数来释放对象的内存空间,因此,编译器不会在栈上为对象分配内存。

方法1问题:

1. 将析构函数设置为私有,调用delete删除对象的时候,delete也需要调用析构函数,所以无法调用delete。需要多创建一个destroy()函数来释放对象所占有的资源。

2. 将析构函数设置为私有,那么当此类作为基类时,析构函数需要设置为虚函数,派生类无法访问基类的构造函数,无法实现多态。

方法2:

针对方法1的问题,可以将构造函数和析构函数都设置为protected,并在类内部用create(), destroy()函数创建和销毁对象,这样可以保证对象在堆创建,同时也能让子类访问析构函数。

2.2.2 限定对象只能在栈上创建

可以将operator new设为私有,如以下代码:

class A
{
private:
    void *operator new(size_t t) {}    // 注意函数的第一个参数和返回值都是固定的
    void operator delete(void *ptr) {} // 重载了 new 就需要重载 delete
public:
    A() {}
    ~A() {}
};

3. 深拷贝和浅拷贝

  • 拷贝构造函数就是浅拷贝
  • 深拷贝需要自己在拷贝构造函数中实现

4. 静态成员

4.1 静态成员变量

所有对象都共享同一份数据, 且编译阶段就分配了内存(分配到了全局区). 类内进行声明, 在类外进行初始化.

4.2 静态成员函数

静态成员函数只能访问静态成员变量.

5. 类所占用的空间大小

  • 类中只有类的非静态数据成员占用类的对象的空间, 而静态数据成员以及成员函数都是分开存储的, 其所有对象都共享静态数据成员以及成员函数.
  • 空类占用一个字节, 为了区分对象.
  • 由于类初始化对象之后, 对象中只存储自身的非静态数据成员, 而成员函数是分开存储的, 对象调用自身成员函数时是将自身的this指针传进成员函数中, 便于其区分是哪个实例化的对象来调用, 所以当有如下代码时:
class Circle {
public:
    void showClassName() {
        printf("this is Circle class");
    }
    void showR() {
        printf("R: %d", m_R);
    }
private:
    int m_R;
};

int main() {
    Circle* pCircle1 = NULL;
    pCircle1->showClassName(); //不会报错, 虽然传入成员函数的this指针是NULL, 但是并没有用
                               //到this指针访问其非静态数据成员
    pCircle1->showR();         //报错, 因为成员函数内部访问了m_R, 会转换成访问this->m_R, 
                               //由于this是空指针, 所以会报错
}

6. const修饰

6.1 const修饰成员函数

const修饰成员函数叫做常函数(const放在形参列表后面, 本质是把this指针修饰为其指向的对象的值不能修改), 其内部不可以修改数据成员, 除非数据成员前面有mutable关键字, 那么常函数也能修改该成员.

6.2 const修饰对象

如果对象声明的时候用const修饰(常对象), 那么该对象就只能调用成员函数中的常函数. 其数据成员(未被mutable修饰)也不可以修改.

7. 友元

7.1 全局函数作友元

友元函数可以访问类中的私有成员. 把函数在类前面声明一下就可以.

7.2 类作友元

友元类可以访问类中的私有成员. 把friend class +类名在被访问的头部声明一下就可以.

7.3 类中成员函数作友元

8. 继承

9. 多态

你可能感兴趣的:(C++基础,类,c++)