码迷,mamicode.com
首页 > 编程语言 > 详细

C++程序设计(二)

时间:2016-11-08 22:29:18      阅读:216      评论:0      收藏:0      [点我收藏+]

标签:技术分享   const   mod   --   常量   double   mos   执行   文件   

1. 类

class CRectangle {
public:
int w, h;
void Init( int w_, int h_ ) {
w = w_; h = h_;
}
int Area() {
return w * h;
}
int Perimeter() {
return 2 * ( w + h );
}
}; //必须有分号
int main() {
int w, h;
CRectangle r; //r是一个对象
cin >> w >> h;
r.Init(w, h);
cout << r.Area() << endl << r. Perimeter();
return 0;
}

类定义的变量 -> 类的实例 -> “对象

对象的大小 = 所有成员变量的大小之和。E.g. CRectangle类的对象, sizeof(CRectangle) = 8

对象之间可以用 ‘=’ 进行赋值

  1. 访问类的成员变量和成员函数
    用法1: 对象名.成员名
    CRectangle r1, r2;
    r1.w = 5;
    r2.Init(3,4);

    用法2: 指针->成员名

    CRectangle r1, r2;
    CRectangle * p1 = & r1;
    CRectangle * p2 = & r2;
    p1->w = 5;
    p2->Init(3,4); //Init作用在p2指向的对象上

    用法3: 引用名.成员名

    CRectangle r2;
    CRectangle & rr = r2;
    rr.w = 5;
    rr.Init(3,4); //rr的值变了,r2的值也变
  2. 类的成员函数的另一种写法
    class CRectangle
    {
        public:
        int w, h;
        int Area(); //成员函数仅在此处声明
        int Perimeter() ;
        void Init( int w_, int h_ );
    };
    int CRectangle::Area() {
      return w * h;
    }
    int CRectangle::Perimeter() {
      return 2 * ( w + h );
    }
    void CRectangle::Init( int w, int h) {
      this->w = w; this->h = h;
    }

2. 类成员的可访问范围

private: 指定私有成员, 只能在成员函数内被访问
public: 指定公有成员, 可以在任何地方被访问
protected:指定保护成员

缺省为私有成员!

 

对象成员的访问权限:
类的成员函数内部, 可以访问:当前对象的全部属性, 函数; 同类其它对象的全部属性, 函数
类的成员函数以外的地方只能够访问该类对象的公有成员

 

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); //ok
}
void CEmployee::getName( char * name) {
  strcpy( name, szName); //ok
}
void CEmployee::averageSalary(CEmployee e1,CEmployee e2){
    salary = (e1.salary + e2.salary )/2;
}
int main(){
    CEmployee e;
    strcpy(e.szName,"Tom1234567889"); //编译错, 不能访问私有成员
    e.setName( "Tom"); // ok
    e.salary = 5000; //ok
    return 0;
}

 

设置私有成员的目的:强制对成员变量的访问一定要通过成员函数进行
设置私有成员的机制 -- 隐藏

2. 构造函数

成员函数的一种:

  • 名字与类名相同,可以有参数,不能有返回值(void也不行)
  • 作用是对对象进行初始化,如给成员变量赋初值
  • 如果定义类时没写构造函数,则编译器生成一个默认的无参数的构造函数
  • 默认构造函数无参数,不做任何操作
  • 如果定义了构造函数,则编译器不生成默认的无参数的构造函数
  • 对象生成时构造函数自动被调用。对象一旦生成,就再也不能在其上执行构造函数
  • 一个类可以有多个构造函数,参数个数或类型不同
class Complex {
private :
    double real, imag;
public:
void Set( double r, double i);
}; //编译器自动生成默认构造函数

Complex c1; //默认构造函数被调用
Complex * pc = new Complex; //默认构造函数被调用
class Complex { 
private : 
    double real, imag; 
public: 
    Complex( double r, double i = 0); 
}; 

Complex::Complex( double r, double i) { 
    real = r; imag = i;
 } 

Complex c1; // error, 缺少构造函数的参数 
Complex * pc = new Complex; // error, 没有参数 
Complex c1(2); // OK 
Complex c1(2,4), c2(3,5); 
Complex * pc = new Complex(3,4);
class Complex { 
private : 
    double real, imag; 
public: 
    void Set( double r, double i ); 
    Complex(double r, double i ); 
    Complex (double r ); 
    Complex (Complex c1, Complex c2); 
}; 

Complex::Complex(double r, double i) { 
    real = r; imag = i; }

Complex::Complex(double r){
    real = r; imag = 0;
}
Complex::Complex (Complex c1, Complex c2){
    real = c1.real+c2.real;
    imag = c1.imag+c2.imag;
}

Complex c1(3) , c2(1,0), c3(c1,c2);

 

构造函数在数组中使用

class CSample { 
    int x; 
public: 
    CSample() { 
        cout << "Constructor 1 Called" << endl; 
    } 
    CSample(int n) { 
        x = n; cout << "Constructor 2 Called" << endl; 
    } 
};

int main(){                                
    CSample array1[2];    
    cout << "step1"<<endl;
    CSample array2[2] = {4,5};
    cout << "step2"<<endl;
    CSample array3[2] = {3};
    cout << "step3"<<endl;
    CSample * array4 =
    new CSample[2];
    delete []array4;
    return 0;
}
输出:
Constructor 1 Called
Constructor 1 Called
step1
Constructor 2 Called
Constructor 2 Called
step2
Constructor 2 Called
Constructor 1 Called
step3
Constructor 1 Called
Constructor 1 Called
class Test {
public:
    Test( int n) { } //(1)
    Test( int n, int m) { } //(2)
    Test() { } //(3)
};

Test array1[3] = { 1, Test(1,2) };
// 三个元素分别用(1),(2),(3)初始化
Test array2[3] = { Test(2,3), Test(1,2) , 1};
// 三个元素分别用(2),(2),(1)初始化
Test * pArray[3] = { new Test(4), new Test(1,2) };
//两个元素分别用(1),(2) 初始化

3. 内联成员函数

  • inline + 成员函数
  • 成员函数声明时便定义时,自动成为内联函数

4. 成员函数的重载及参数缺省

#include <iostream>
using namespace std;
class Location {
private :
    int x, y;
public:
    void init( int x = 0 , int y = 0 );
    void valueX( int val ) { x = val ; }
    int valueX() { return x; }
};

void Location::init( int X, int Y){
    x = X;
    y = Y;
}
int main() {
    Location A;
    A.init(5);
    A.valueX(5);
    cout << A.valueX();
    return 0;
}

4. 复制构造函数

  • 只有一个参数,即对同类对象的引用
  • 形如 X::X( X& )X::X(const X &), 二者选一,后者能以常量对象作为参数
  • 如果没有定义复制构造函数,那么编译器生成默认复制构造函数。默认的复制构造函数完成复制功能。
  • 如果定义的自己的复制构造函数, 则默认的复制构造函数不存在。
class Complex { 
public :
    double real,imag; 
    Complex(){ } 
    Complex( const Complex & c ) {
        real = c.real; 
        imag = c.imag; 
        cout << “Copy Constructor called”; } 
}; 

Complex c1;
Complex c2(c1);//调用自己定义的复制构造函数,输出 Copy Constructor called

复制构造函数起作用的三种情况
1)当用一个对象去初始化同类的另一个对象时。
2)如果某函数有一个参数是类 A 的对象, 那么该函数被调用时,类A的复制构造函数将被调用。
3) 如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数被调用.

5. 类型转换构造函数

目的:实现类型的自动转换
特点:只有一个参数,不是复制构造函数

当使用类型转换构造函数的时候,编译器会自动调用这个转换构造函数,建立一个临时对象/临时变量。

class Complex {
public:
    double real, imag;
    Complex( int i ) { //类型转换构造函数
        cout << “IntConstructor called” << endl;
        real = i; imag = 0;
    }
Complex( double r, double i ){
    real = r;
    imag = i; }
};

int main () {
    Complex c1(7, 8);
    Complex c2 = 12;
    c1 = 9; // 9被自动转换成一个临时Complex对象
    cout << c1.real << "," << c1.imag << endl;
    return 0;
}        

6. 析构函数

成员函数的一种

  • 名字与类名相同,在前面加‘~
  • 没有参数和返回值
  • 一个类最多只有一个析构函数
  • 对象消亡时被自动调用
  • 定义类时没写析构函数, 则编译器生成缺省析构函数(不涉及释放用户申请的内存释放等清理工作)
  • 定义了析构函数, 则编译器不生成缺省析构函数

// 对象数组生命期结束时, 对象数组的每个元素的析构函数都会被调用
class Ctest {
public:
    ~Ctest() { cout<< "destructor called" << endl; }
};
int main () {
    Ctest array[2];
    cout << "End Main" << endl;
    return 0;
}
delete 运算导致析构函数调用
Ctest * pTest;
pTest = new Ctest; //构造函数调用
delete pTest; //析构函数调用
------------------------------------------------------------------
pTest = new Ctest[3]; //构造函数调用3次
delete [] pTest; //析构函数调用3次

构造函数和析构函数 调用时机的例题

class Demo {
    int id;
public:
    Demo( int i ){
    id = i;
    cout << “id=” << id << “ Constructed” << endl;
    }
    ~Demo(){
    cout << “id=” << id << “ Destructed” << endl;
    }
};    
                                 输出:                              
Demo d1(1);                           id=1 Constructed           
void Func(){                          id=4 Constructed
    static Demo d2(2);                     id=6 Constructed  
    Demo d3(3);                         id=6 Destructed
    cout << “Func” << endl;                  main
}                                 id=5 Constructed
int main (){                           id=5 Destructed
    Demo d4(4);                         id=2 Constructed              
    d4 = 6;                           id=3 Constructed
    cout << “main” << endl;                  Func
    { Demo d5(5); }                       id=3 Destructed
    Func();                           main ends
        cout << “main ends” << endl;             id=6 Destructed
    return 0;                          id=2 Destructed
}                                  id=1 Destructed

7. 静态成员变量和静态成员函数

静态成员:在说明前面加了static关键字的成员。

class CRectangle { 
private: 
    int w, h; 
    static int nTotalArea; //静态成员变量 
    static int nTotalNumber; 
public: 
    CRectangle(int w_,int h_); 
    ~CRectangle(); 
    static void PrintTotal(); //静态成员函数 
};

普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。

  • sizeof 运算符不会计算静态成员变量。
  • 普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。
  • 普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用与某个对象。因此静态成员不需要通过对象就能访问。
  • 静态成员变量本质上是全局变量,哪怕一个对象都不存在,类的静态成员变量也存在。静态成员函数本质上是全局函数。
  • 在静态成员函数中,不能访问非静态成员变量, 也不能调用非静态成员函数。
class CRectangle
{
private:
    int w, h;
    static int nTotalArea;
    static int nTotalNumber;
public:
    CRectangle(int w_,int h_);
    ~CRectangle();
    static void PrintTotal();
};

CRectangle::CRectangle(int w_,int h_) { 
    w = w_; h = h_; nTotalNumber ++; nTotalArea += w * h; 
} 

 CRectangle :: CRectangle(CRectangle & r ) {
    w = r.w; h = r.h; nTotalNumber ++; nTotalArea += w * h;

 }


CRectangle::~CRectangle() { 
    nTotalNumber --; nTotalArea -= w * h; 
} 
void CRectangle::PrintTotal() { 
    cout << nTotalNumber << "," << nTotalArea << endl; 
}


int CRectangle::nTotalNumber = 0;
int CRectangle::nTotalArea = 0;
// 必须在定义类的文件中对静态成员变量进行一次说明或初始化。否则编译能通过,链接不能通过。
int main(){
    CRectangle r1(3,3), r2(2,2);
    //cout << CRectangle::nTotalNumber; // Wrong , 私有
    CRectangle::PrintTotal();
    r1.PrintTotal();
    return 0;
}
输出结果:
2,13
2,13

 8. 成员对象和封闭类

成员对象: 一个类的成员变量是另一个类的对象,包含 成员对象 的类叫 封闭类 (Enclosing)

class CTyre { //轮胎类
private:
    int radius; //半径
    int width; //宽度
public:
    CTyre(int r, int w):radius(r), width(w) { }
};
class CEngine { //引擎类 }; class CCar { //汽车类 ? “封闭类” private: int price; //价格 CTyre tyre; CEngine engine; public: CCar(int p, int tr, int tw); }; CCar::CCar(int p, int tr, int w):price(p), tyre(tr, w){ }; int main(){ CCar car(20000,17,225); return 0; }

定义封闭类的构造函数时, 添加初始化列表:

类名::构造函数(参数表):成员变量1(参数表), 成员变量2(参数表), …
{
…
}

调用顺序

当封闭类对象生成时,
?S1: 执行所有成员对象 的构造函数
?S2: 执行 封闭类 的构造函数

成员对象的构造函数调用顺序
?和成员对象在类中的声明顺序一致
?与在成员初始化列表中出现的顺序无关

当封闭类的对象消亡时,
?S1: 先执行 封闭类 的析构函数
?S2: 执行 成员对象 的析构函数
析构函数顺序和构造函数的调用顺序相反

class CTyre {
public:
    CTyre() { cout << "CTyre contructor" << endl; }
    ~CTyre() { cout << "CTyre destructor" << endl; }
};
class CEngine {
public:
    CEngine() { cout << "CEngine contructor" << endl; }
    ~CEngine() { cout << "CEngine destructor" << endl; }
};

class CCar {
private:
    CEngine engine;
    CTyre tyre;
public:
    CCar( ) { cout << “CCar contructor” << endl; }
    ~CCar() { cout << "CCar destructor" << endl; }
};
int main(){
    CCar car;
    return 0;
}
程序的输出结果是:
CEngine contructor
CTyre contructor
CCar contructor
CCar destructor
CTyre destructor
CEngine destructor

9. 友元

一个类的友元函数可以访问该类的私有成员

class CCar; //提前声明 CCar类, 以便后面CDriver类使用
class CDriver {
public:
    void ModifyCar( CCar * pCar) ; //改装汽车
};
class CCar {
private:
    int price;
    friend int MostExpensiveCar( CCar cars[], int total); //声明友元
    friend void CDriver::ModifyCar(CCar * pCar); //声明友元
};

void CDriver::ModifyCar( CCar * pCar)
{
    pCar->price += 1000; //汽车改装后价值增加
}
int MostExpensiveCar( CCar cars[], int total) //求最贵汽车的价格
{
    int tmpMax = -1;
    for( int i = 0; i < total; ++i )
    if( cars[i].price > tmpMax)
    tmpMax = cars[i].price;
    return tmpMax;
}
int main(){
    return 0;
}

将一个类的成员函数(包括构造, 析构函数)声明为另一个类的友元

class B {
public:
    void function();
};
class A {
    friend void B::function();
};

A是B的友元类 则A的成员函数可以访问B的私有成员

class CCar {
private:
    int price;
    friend class CDriver; //声明CDriver为友元类
};
class CDriver {
public:
    CCar myCar;
    void ModifyCar() { //改装汽车
        myCar.price += 1000; // CDriver是CCar的友元类?可以访问其私有成员
    }
};

int main() { 
    return 0; 
}

注意:友元类之间的关系不能传递, 不能继承

10. this指针

技术分享

其作用就是指向成员函数所作用 的对象。

非静态成员函数中可以直接使用this来代表指向该函数作用的对象的指针。

class Complex {
public:
    double real, imag;
    void Print() { cout << real << "," << imag ; }
    Complex(double r,double i):real(r),imag(i){ }
    Complex AddOne() {
        this->real ++; //等价于 real ++;
        this->Print(); //等价于 Print
        return * this;
    }
};

int main() {
    Complex c1(1,1),c2(0,0);
    c2 = c1.AddOne();
    return 0;
} //输出 2,1

技术分享技术分享

静态成员函数中不能使用 this 指针!
因为静态成员函数并不具体作用与某个对象!
因此,静态成员函数的真实的参数的个数,就是程序中写出的参数个数!

C++程序设计(二)

标签:技术分享   const   mod   --   常量   double   mos   执行   文件   

原文地址:http://www.cnblogs.com/xuanyuyt/p/6044367.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!