[C++学习笔记05]对象的使用
- static成员
普通static成员
必须在类体外定义。
特殊static const成员
整型(int,char,short,long等)static const成员
可以不需要在类体外定义,如果没有在类外部初始化,必须在类体内初始化(常量)。
非整型static const成员
非整型不能像整型那样,不允许在类体初始化,只能在类外定义初始化。
#include <iostream> using namespace std; class Test { public: static int a; // 1普通的static成员变量,不能在类体内初始化 static const int b=10; // 2static const int(整型), 可以不需要在类体外定义,如果没有在类外部初始化,必须在类体内初始化(常量) static const double c; // 3static const double 非整型不能像整型那样,不允许在类体初始化 static const char d=11; // 2char和int都是整型 一样的,可以不需要在类体外定义,如果没有在类外部初始化,必须在类体内初始化(常量) }; int Test::a; // 1普通的static成员必须在类体外定义,可以不需要初始化,默认值0 const double Test::c=10; // 3static const double 非整型必须在类体外定义(并必须初始化) int main(void) { Test a; cout << a.a << endl; cout << a.b << endl; cout << a.c << endl; cout << Test::d << endl;return 0; }
- static成员函数
static成员函数没有this指针
非静态成员函数可以访问静态成员
静态成员函数不可以访问非静态成员 - 类/对象大小计算
类大小计算遵循前面学过的结构体对齐原则类的大小与数据成员有关与成员函数无关类的大小与静态数据成员无关虚函数对类的大小有影响(虚表指针)虚继承对类的大小有影响 - 四种对象作用域与生存期
说明:作用域和生存期不总是等同的。
栈对象隐含调用构造函数(程序中没有显示调用)堆对象隐含调用构造函数(程序中没有显示调用)全局对象、静态全局对象全局对象的构造先于main函数已初始化的全局变量或静态全局对象存储于.data段中未初始化的全局变量或静态全局对象存储于.bss(block started by symbol)段中静态局部对象已初始化的静态局部变量存储于.data段中未初始化的静态局部变量存储于.bss段中
关于.bss,.data段的区别
.bss可执行文件中不占用空间,因为初始值为0,只需要一个符号。block started by symbol,程序加载才分配.bss段。
.data可执行文件中占用空间。
关于静态普通对象与静态类对象初始化的区别
- static用法总结
C语言中
1.用于修饰函数内部的变量,延长变量的生存期,使得函数有一定的“状态”。属于不可重入函数(线程不安全函数)。
2.在文件中修饰变量或者函数,使之只在本文件中可见,具有internal linkage,别的文件extern是不行的。
C++语言中
除了C语言中的两种用法在加上类中的成员变量与成员函数的修饰。
注:如果在.h文件中定义全局变量会导致多个源文件包含时重定义,最好的做法是在一个源文件中定义全局变量,另一个源文件中使用extern(称为external linkage),也可以在.h中使用extern语句,当然在.h中定义全局静态变量是不会出现重定义的。 - static与单例模式
实现单例模式的几点注意:
1.保证一个类只有一个实例,并提供一个全局访问点;
2.禁止拷贝(将拷贝构造函数与=数声明为private,并且不需要提供实现)。
实现单例模式的方式:
1.通过像定义getInstance一样的静态函数实现手动的Free静态函数即可,当你要析构对象,直接调用Free函数即可。
2.通过嵌套类,外围类中定义一个嵌套类的静态成员,在嵌套类中的析构函数中delete instance即可。
class Singleton { public: Singleton() { cout << "Singleton ... " << endl; } static Singleton *getInstance() { if (instance_ == NULL) { instance_ = new Singleton; } return instance_; } ~Singleton() { cout << "~Singleton ... " << endl; } // 嵌套类实现析构 class Garbo { public: ~Garbo() { if (instance_ != NULL) { delete instance_; } } }; private: static Singleton *instance_; // 1不能析构 static Garbo gb_; Singleton(const Singleton &s); Singleton &operator=(const Singleton &s); }; Singleton *Singleton::instance_; // 1不能析构 Singleton::Garbo gb_; // 通过使用嵌套类来实现程序结束,自动析构单例对象 int main(void) { Singleton *s1 = Singleton::getInstance(); Singleton *s2 = Singleton::getInstance(); //Singleton s3(*s1); // 防止拷贝 //Singleton s3; //s3 = *s1; // 防止拷贝 return 0; }
3. 直接通过在函数中定义一个static的对象,然后返回引用或者指针(较为简单的方式)
class Singleton { public: Singleton() { cout << "Singleton ... " << endl; } static Singleton &getInstance() { // 直接通过在函数中定义一个static的对象,然后返回引用或者指针都行,比较简单的方式 // 当程序结束时,instance自动析构 static Singleton instance; return instance; } ~Singleton() { cout << "~Singleton ... " << endl; } private: Singleton(const Singleton &s); Singleton &operator=(const Singleton &s); }; int main(void) { Singleton &s1 = Singleton::getInstance(); Singleton &s2 = Singleton::getInstance(); return 0; }
- const成员函数
const成员函数与非const成员函数构成函数重载;
const成员函数只能访问数据成员的值,而不能修改它;
const成员数可以修改使用mutable关键字修饰的成员变量;
const对象只能调用const成员函数,非const对象既能调用const成员函数,也能调用非const成员函数。
class Test { public: Test(int num = 0) : num_(num) { count_ = 0; } // const 成员函数与非const成员函数构造函数重载 // 非const对象调用非const成员函数,也可以调用const成员函数,const对象只能调用const成员函数 int getNum() { cout << "getNum()" << endl; count_++; return num_; } int getNum() const { cout << "getNum() const" << endl; count_++; return num_; } void showCount() const { cout << count_ << endl; } private: int num_; mutable int count_; // count只是用来统计获取的次数,希望在const成员函数中修改。 }; int main(void) { Test t; t.getNum(); // const 对象 const Test t2; t2.getNum(); t2.getNum(); t2.getNum(); t2.showCount(); return 0; }