声明与定义



变量的声明(如:extern int a;声明外部变量)告诉编译器变量名字与类型;



变量的定义:为变量分配存储空间,此时也可以给定初始值;



函数的声明:告诉编译器有这么一个函数;



函数的定义:实现函数,简言之就是带有{ };



 



与结构体一样,类只是一种复杂数据类型的声明,不占用内存空间。



而对象是类这种数据类型的一个变量,或者说是通过类这种数据类型定义了一个变量(对象),是占用内存空间的。



calss Point{



};



 



Point t1; // 将调用构造函数



Point *t1;// 不调用构造函数



 



声明一个指针 int *p;表示*p的类型为int,p是指向int类型的指针;(即p为int* ; *p为int)



定义 int *p 时,p位于栈区,占有内存空间是系统分配,系统将给定一个随机地址(不确定地址)给p;



void main_5()
 
  
{
 
  
    int *p;     
 
  
    printf("0x%x \n", p);
 
  
*p = 5;
 
  
// 若无上句的赋值(给确切的内存地址),将非法访问内存,程序奔溃
 
  
}



二、临时变量的产生



函数返回时、类型转换时、形式参数为const时;



1、函数返回时,以值或是指针形式返回时;



int sum(int a,int b)
 
  
{
 
  
    return a + b;//编译器会将结果a+b的值拷贝给临时变量,最终返回的是临时变量;
 
  
}

2、在进行 强制类型转换时;



double a = 10.5;



cout << (int)a ;// 在强转时,一定生成临时变量,原始数据本身并没有改变。



cout << a;



3、函数形参为const来保护原始数据;



 



 



 



 



三、初始化



C++的初始化方式:默认初始化、值初始化、直接初始化、拷贝初始化、列表初始化;



 



默认初始化



1、未初始化的 全局内置类型(int、double)变量;



2、类 类型,都会执行默认构造函数;如string、vector<int>;



 



值初始化



值初始化是值使用了初始化器(即使用了圆括号或花括号)但却没有提供初始值的情况;


vector<int> v1(10);//10个元素,每个元素的初始化为0
 
  
vector<string> v2(10);//10个元素,每个元素都为空
 
  
vector<int> v4(10, 1);//v3有10个元素,每个的值都是1
 
  
vector<int> v3{10};//v2有1个元素,该元素的值是10
 
  
vector<int> v5{10, 1};//v4有2个元素,值分别是10和1
 
  
int *p = new int();



 



直接初始化



直接初始化是指采用小括号()而不使用等号=的方式进行变量初始化;



string str1(10,'9');//直接初始化



string str2(str1);//直接初始化



 



 



拷贝初始化



使用等号(赋值号=)进行初始化,编译器把等号右侧的初始值拷贝到新创建的对象中去,拷贝初始化通常使用拷贝构造函数来完成。拷贝初始化看起来像是给变量赋值,实际上是执行了初始化操作,与先定义再赋值本质不同。


int a = 0;
 
  
int a = {0};
 
  
string str1 = "hello";
 
  
string s=string("123456");



初始化列表



为C++11采用的初始化方式,使用{}进行初始化操作,下列三种情况需要用到初始化成员列表:



1、 类的数据成员中含有不带默认构造函数的 对象 (包括在继承时显示调用父类的构造函数对父类成员初始化);



2、 类的数据成员中含有 const修饰类型 的或 引用类型 ;(因为这两种对象要在声明后马上初始化);



3、 子类初始化父类的私有成员;


vector<int> v4{1, -2, 3, 10, -4}; // 等价于 v4 = {1, 2, 3, ....} 
 
  
int b[5]{10,20,30,40,50}; // a[] = {10,20,30,40,50};
 
  

      
  
 
  
class People{
 
  
    public:
 
  
People(string n="", int a = -1) : age(a), name(n){} // 列表初始化
 
  
    private:
 
  
        string name;
 
  
        int age;
 
  
};



 



注意:初始化列表中变量的执行顺序是由成员变量的声明顺序来决定的,上述并不先执行age(a),而是先执行name(n);



 



【举例1】


class A {
 
  
    ...
 
  
    private:
 
  
       int &a;
 
  
};
 
  
class B : public A {
 
  
    ...
 
  
    private:
 
  
         int a;
 
  
    public:
 
  
         const int b; // 数据成员中含有const修饰类型的或引用类型,必须通过初始化列表来初始化;
 
  
         A c; // 数据成员中含有不带默认构造函数的对象,必须通过初始化列表来初始化;
 
  
         static const char* d;
 
  
         A* e;
 
  
};

 



类对象的显式初始化



Data data1(2019,9,22);//显式初始化,直接调用构造函数



Data* b = new Data(2019,9,22);//显式初始化,直接调用构造函数,使用delete时析构



Data p = Data(2019,9,22);//显式初始化,直接调用构造函数,没有临时对象,作用域结束时析构



Data B(data1);//显式初始化,调用拷贝构造函数,作用域结束时析构



 



 



类对象的隐式初始化



Data b = a;//用一个对象隐式初始化另一对象,调用拷贝构造函数,作用域结束时析构



 



 



 



 



 



C++11  initialize_list类模板( 初始化类模板 #include<initalize_list>



 


#include <iostream>
 
  
#include <vector>
 
  
class MyNumber
 
  
{
 
  
public:
 
  
    MyNumber(const std::initializer_list<int> &v) {// C++11允许构造函数和其他函数把初始化列表当做参数。
 
  
        for (auto itm : v) {
 
  
            mVec.push_back(itm);
 
  
        }
 
  
    }
 
  
    void print() {
 
  
    for (auto itm : mVec) {
 
  
        std::cout << itm << " ";
 
  
    }
 
  
  }
 
  
private:
 
  
    std::vector<int> mVec;
 
  
};
 
  

      
  
 
  
int main()
 
  
{
 
  
    MyNumber m{ 1, 2, 3, 4 }; // calls initializer_list
 
  
    m.print();  // 1 2 3 4
 
  
    
 
  
    MyNumber m2{ 10, 20, 30, 40 }; // calls initializer_list
 
  
    m2.print();  // 10 20 30 40
 
  

      
  
 
  
    return 0;
 
  
}