C++类


类和对象初步
面向对象的程序设计的基本特点:抽象,封装,继承,多态

类的定义:
class 类名{
    访问范围说明符:
     成员变量;
  ......
  成员函数;
  ......
};
访问范围一共有三种:public,private,protected

成员变量、成员函数的写法与普通的变量、函数相同。

一个类的成员函数之间可以相互调用。类的成员函数可以重载 ,也可以设定函
数的默认值。

成员函数的定义可以在类外:
返回值类型 类名::函数名{
    函数体;

所谓成员函数作用于某个对象上,指的是进入该成员函数时,函数中访问到的成
员变量是属于该对象的。

访问对象成员:
    对象名.成员名

    对象指针->成员名
 
和结构变量一样,对象之间可以使用"="相互赋值,但不能进行比较运算

#include <iostream>

using namespace std;

// 矩形类 
class CRectangle{
    public:
        int w, h;
        void init(int w_, int h_);   // 设置宽度和高度 
        int area();                  // 求面积 
        int perimeter();             // 求周长 
}; 

void CRectangle::init(int w_, int h_){
    w = w_;
    h = h_; 
}

int CRectangle::area(){
    return w*h;
}

int CRectangle::perimeter(){
    return 2*(w + h);
}

int main()
{
    int w, h;
    CRectangle r;
    cin >> w >> h;
    r.init(w, h);
    cout << "It's area is " << r.area() << endl;
    cout << "It's perimeter is " << r.perimeter() << endl;
    cout << sizeof(CRectangle) << endl;
    
    return 0;
}

类成员的访问范围:
    访问范围一共有三种:public,private,protected
    public: 指定公有成员,一个类的公有成员在任何地方都可以被访问
    private:用来指定私有成员,不论是成员变量还是成员函数,都只能在
 该类的成员函数内部才能被访问
     设置私有成员的机制叫做隐藏,隐藏的目的是强制对变量成员的访问
  要通过成员函数进行。这样做的好处是如果以后修改了成员变量的类
  型等属性,只需修改成员函数即可。否则需要修改所有访问成员变量
  的语句。
  隐藏机制可以避免对对象的不正确操作。
 protected:用来指定保护成员
 
 如果某个成员前面没有访问范围说明符,则对于class默认为私有成员
 

#include <iostream>
#include <cstring>

using namespace std;

class CEmployee{
    private:
        char szName[30];
    public:
        int salary;
        void setName(char *name);
        void getName(char *name);
        void averageSalary(CEmployee e1, CEmployee e2);
};

void CEmployee::setName(char *name){
    strcpy(szName, name);
}

void CEmployee::getName(char *name){
    strcpy(name, szName);
}

void CEmployee::averageSalary(CEmployee e1, CEmployee e2){
    salary = (e1.salary + e2.salary) / 2;
}

int main()
{
    CEmployee e;
    // strcpy(e.szName, "Tom");  error,不能访问私有成员 
    e.setName("Tom");
    e.salary = 50000;
    
    return 0;
}

 构造函数:
    面向对象的程序设计语言倾向于对象一定要经过初始化后,使用起来才比较安全,因此才引入构造函数
 这一概念用于对对象进行自动初始化。
 构造函数是一类特殊的成员函数,其名字和类的名字一样,不写返回值类型,可以重载。
 如果类的设计者没有写构造函数,那么编译器会自动生成一个没有参数的构造函数。
 无参构造函数,不论是编译器自动生成的还是程序员写的,都称为默认构造函数。
 对象在生成时,一定会自动调用某个构造函数进行初始化,对象一旦生成,就再也不会在其上执行构造
 函数。

#include <iostream>

using namespace std;

class Complex{
    private:
        double real, imag;
    public:
        // 构造函数
        Complex(double r);
        Complex(double r, double i);
        Complex(Complex c1, Complex c2);
};

Complex::Complex(double r){
    real = r;
    imag = 0;
    cout << "1" << endl; 
}   

Complex::Complex(double r, double i){
    real = r;
    imag = i;
    cout << "2" << endl;
}

Complex::Complex(Complex c1, Complex c2){
    real = c1.real + c2.real;
    imag = c1.imag + c2.imag;
    cout << "3" << endl;
}

int main()
{
    Complex c1(3), c2(1, 2), c3(c1, c2), c4 = 7;
    
    return 0;
}

 复制构造函数:
    复制构造函数时构造函数的一种,也称拷贝构造函数,它只有一个参数,参数类型是本类的引用。
 如果类的设计者不写复制构造函数,编译器会自动生成复制构造函数,它的作用是实现从源对象到目标对象
 逐个字节的复制。编译器自动生成的复制构造函数称为默认复制构造函数。默认构造函数不一定存在,但复
 制构造函数总会存在。
 复制构造函数的参数可以是const引用,也可以是非const引用。一般使用const引用,这样既可以使用常量作
 为参数,也可以使用非常量对象作为参数去初始化其它对象。
 
复制构造函数被调用的三种情况:
    1)用一个对象去初始化同类的另一个对象
    2)作为形参的对象,用复制构造函数初始化的,而且调用复制构造函数时的参数,就是调用函数时所给的参数
    3)作为函数返回值的对象是用复制构造函数初始化的,而调用复制构造函数时的实参,就是return语句返回的
          对象

#include <iostream>

using namespace std;

class Complex{
    public:
        double real, imag;
        Complex(double r, double i){
            real = r;
            imag = i;
        }
    // 无复制构造函数 
};

class Complex2{
    public:
        double real, imag;
        Complex2(double r, double i){
            real = r;
            imag = i;
        }
        Complex2(const Complex & c){    // 复制构造函数 
            real = c.real;
            imag = c.imag;
            cout << "Flag" << endl;
        } 
};

int main()
{
    Complex c1(1, 2);   // 调用构造函数初始化 
    Complex c2(c1);     // 用默认复制构造函数初始化
    
    Complex2 c_1(1, 2);
    Complex2 c_2(c_1); 
    
    return 0;
} 

 类型转换构造函数:
    只有一个参数的构造函数一般都可以称作类型转换构造函数,因为这样的构造函数能够起到类型
 自动转换的作用

析构函数:
    成员函数的一种,它的名字与类名相同,但前面要加"~",没有参数和返回值。一个类有且仅有一个
 析构函数。如果定义类时没有写析构函数,则编译器生成默认析构函数。
 析构函数在对象消亡时自动被调用。可以定义析构函数在对象消亡后做善后工作。
 函数的参数对象以及作为函数返回值的对象,在消亡时也会引发析构函数调用。

#include <iostream>

using namespace std;

class String{
    private:
        char *p;
    public:
        String(int n);    // 构造函数  
        ~String();        // 析构函数 
}; 

String::String(int n){
    p = new char[n];
} 

String::~String(){        //  利用析构函数释放所分配的动态内存 
    delete []p;
    cout << "Flag" << endl;    // 用于测试的标记 
}

int main()
{
    String array[2] = {2, 2};
    String * pTest = new String(2);
    delete pTest;
    
    return 0;
}

构造函数、析构函数和变量的生存周期

#include <iostream>

using namespace std;

class Demo{
    private:
        int id;
    public:
        Demo(int i){
            id = i;
            cout << "id = " << id << "constructed" << endl;
        } 
        
        ~Demo(){
            cout << "id = " << id << "destructed" << endl;
        }
};

Demo d1(1);

void Func(){
    static Demo d2(2);
    Demo d3(3);
    cout << "func" << endl;
}

int main()
{
    Demo d4(4);
    d4 = 6;
    cout << "main" << endl;
    Func();
    cout << "main ends" << endl;
    
    return 0;
}

/*
输出结果:
    id = 1constructed
    id = 4constructed
    id = 6constructed
    id = 6destructed
    main
    id = 2constructed
    id = 3constructed
    func
    id = 3destructed
    main ends
    id = 6destructed
    id = 2destructed
    id = 1destructed 
*/ 

 

posted @ 2017-09-10 17:08  荒唐了年少  阅读(176)  评论(0编辑  收藏  举报