Archive for the ‘C++’ Category

C++ Tutorial

Posted: April 6, 2011 in C++

//#ifdef GUARDIAN_H
//#define GUARDIAN_H

#include <iostream>
#include <string>
using namespace std;

class Guardian
{
private:
 string GFirstName,GLastName,GId,GPhone,GAddress;

public:
 
 Guardian();//default constructor
 Guardian(string FirstName,string LastName,string Id,string Phone,string Address);
 void setFirstName(string FirstName);
 string getFirstName();

 void setLastName(string LastName);
 string getLastName();

 void setId(string Id);
 string getId();

 void setPhone(string Phone);
 string getPhone();

 void setAddress(string Address);
 string getAddress();

};

Guardian::Guardian(){}

Guardian::Guardian(string FirstName, string LastName, string Id, string Phone, string Address)
{GFirstName=FirstName;GLastName=LastName;GId=Id;GPhone=Phone;GAddress=Address;}

void Guardian::setFirstName(string FirstName){GFirstName=FirstName;}
string Guardian::getFirstName(){return GFirstName;}

void Guardian::setLastName(string LastName){GLastName=LastName;}
string Guardian::getLastName(){return GLastName;}

void Guardian::setId(string Id){GId=Id;}
string Guardian::getId(){return GId;}

void Guardian::setPhone(string Phone){GPhone=Phone;}
string Guardian::getPhone(){return GPhone;}

void Guardian::setAddress(string Address){GAddress=Address;}
string Guardian::getAddress(){return GAddress;}
//#endif

==========================================

//#ifndef STUDENT_H //for avoid redefination for the header
//#define STUDENT_H

/*#include <iostream>
#include <string>
using namespace std;*/

#include “Guardian.h”

class Student
{
private:
 string SFirstName,SLastName,SId,SPhone,SAddress;
 
 Guardian G;//set a relationship from Guardian

public:
 Student();//default constructor
 Student(string Id, string Phone,string Address);//set the variable to the constructor

 void setFirstName(string FirstName);
 string getFirstName();

 void setLastName(string LastName);
 string getLastName();

 void setId(string Id);
 string getId();

 void setPhone(string Phone);
 string getPhone();

 void setAddress(string Address);
 string getAddress();

 /*——————Guardian—————————*/
 void setGuardian(Guardian Gd);
 Guardian getGuardian();
 /*——————Guardian—————————*/

};

Student::Student(){}

Student::Student(string Id,string Phone,string Address)//set initialization for constructor
{SId=Id;SPhone=Phone;SAddress=Address;}

void Student::setFirstName(string FirstName){SFirstName=FirstName;}
string Student::getFirstName(){return SFirstName;}

void Student::setLastName(string LastName){SLastName=LastName;}
string Student::getLastName(){return SLastName;}

void Student::setId(string Id){SId=Id;}
string Student::getId(){return SId;}

void Student::setPhone(string Phone){SPhone=Phone;}
string Student::getPhone(){return SPhone;}

void Student::setAddress(string Address){SAddress=Address;}
string Student::getAddress(){return SAddress;}
/*——————Guardian—————————*/
void Student::setGuardian(Guardian Gd){G=Gd;}
Guardian Student::getGuardian(){return G;}
/*——————Guardian—————————*/

//#endif

=========================================

#include “Student.h”

void main()
{
 Student Student1(“TP000001″,”0108888888″,”Bukit Jalil”);//set initialization

 string tmp;

 cout<<“Enter the firstname: “;
 cin>>tmp;
 Student1.setFirstName(tmp);

 cout<<“Enter the lastname: “;
 cin>>tmp;
 Student1.setLastName(tmp);

 cout<<endl<<“Your personal details:”<<endl;
 
 cout<<“Name: “<<Student1.getLastName()<<” ”
  <<Student1.getFirstName()<<endl;
 
 cout<<“ID: “<<Student1.getId()<<endl
  <<“Phone No: “<<Student1.getPhone()<<endl
  <<“Address: “<<Student1.getAddress()<<endl;

 Guardian Guardian1(“Huang”,”FeiHong”,”TP999999″,”0100000001″,”Bukit Jaili”);
 Student1.setGuardian(Guardian1);
 
 cout<<endl<<“Guardian personal details:”<<endl;
 
 cout<<“Name: “<<Student1.getGuardian().getFirstName()<<” ”
  <<Student1.getGuardian().getLastName()<<endl;
 
 cout<<“ID: “<<Student1.getGuardian().getId()<<endl
  
  <<“Phone No: “<<Student1.getGuardian().getPhone()<<endl
  
  <<“Address: “<<Student1.getGuardian().getAddress()<<endl;

 //Guardian Guardian1;
 //Guardian1.setFirstName(“Huang”);
 //Student1.setGuardian(Guardian1);
 //cout<<Student1.getGuardian().getFirstName()<<endl;
}

Advertisements

在介绍本节内容之前先说下(class)和结构(structure)之间的的联系.

关键字classstruct之间基本用法一样,

只是class将成员变量和成员函数区分为了privatepublic,且默认为private.

struct默认为public, 且采用公有继承(public inheritance).

如果将之前所有的class Cat改为struct Cat. 运行后,

将输出进行比较,可以发现没有发生任何变化.

Q: 那为什么要用classstructure来定义相同的功能呢?

A: 其实, C++ 是作为 C 的扩展开发.因而继承了 C语言 的特点,

但是结构中不能使用函数. 所以C++的创始对structure进行扩展.

从而将这种新的扩张功能命名为(class).同时修改了成员的可见性.

并运用到C++语言当中.

==========================================

之前, 介绍了如何新建和删除指针: http://wp.me/p14oGQ-7m

Q: 有没有什么方法可以在自由储存区创建对象呢?

A: 就像可以创建指向整型的指针一样, 也可以创建指向任何数据类型(包括类class)的指针.

比如: 声明一个Cat类, 则可以声明一个指向Cat类的指针, 并在自由存储区中实例化一个Cat对象,

就像在堆栈(stack)中, 创建Cat对象一样. 创建Cat指针的语法和创建int指针相同:

Cat *pCat = new Cat;

这将调用默认构造函数, 不接受任何参数的构造函数.

(关于默认构造函数请访问: http://wp.me/p14oGQ-7P)

每当对象被创建(无论是在自由存储区还是在堆栈中)都将调用构造函数.

然而需要注意的是:

使用new创建对象时, 不仅可以使用默认构造函数, 也可以使用任何构造函数.

_______________________________________________

说完了如何在自由存储区创建对象, 当然也要知道如何删除该对象.

delet对用于指向自由存储区中的对象的指针时, 在释放内存之前将调用对象的析构函数.

这个类提供了一个执行清理工作的机会(通常是释放从堆中分配而来的内存),

就像从堆栈中删除对象一样.

请查看参考代码: NewAndDeleteObject.h

==========================================

现在还要补充一个内容:(★★★) 非常重要且不简单

按值将对象(object)传递给函数(function), 都将创建该对象的副本. 而按值从函数返回一个对象时,将创建另个副本.对于小型对象而言,这样的开销是微不足道的.

而对于用户定义的大型对象(如结构或者类对象),复制的开销可能很高.用户定义的对象在堆栈(stack)中占据的空间是其所有的成员变量所占空间的总和,无论是在性能方面还是再内存方面都是非常昂贵的.

还有另一种开销.没创建这些临时副本时,都要调用一个特殊的构造函数:复制构造函数.函数返回时,临时对象将被销毁,这将调用对象的析构函数.如果函数按值返回对象,就需要创建和销毁该对象的一个副本.

对于大型的对象,调用构造函数和析构函数在速度和内存方面的开销都可能很大.

  

实际的对象可能更大,开销也可能更高,但使用它足以说明复制调用构造函数和析构函数的调用频率.

请查看参考代码: ReferenceEfficiency.h

==========================================

传递 const  指针 :

代码: ReferenceEfficiency.h 中,

虽然给Function2()传递指针的效率更高,但这样做也是危险的.

函数Function2()并不打算对传递给它的Dog对象进行修改,但仍获取了该对象的地址.

这就是原始对象暴露在被修改的危险之中,失去了按值传递提供的保护.

按值传递好比将Dog的资料交给兽医,而对于资料的任何操作都不会对Dog本身产生任何危害.

按引用传递将Dog的位置告诉兽医,让兽医直接到家里来给Dog看病.

(这里证实了我之前的猜测,即对对象本身进行操作.)

解决这个问题的方法是,传递一个指向const Dog对象的指针.

这样做可以防止对Dog对象调用任何非const方法,从而防止对象被改变.

传递const引用好比让兽医能够看到Dog原物, 但是不能对其做任何修改.

请查看参考代码: ConstObjectPointer.h

==========================================

在  9.2 引用=指针>函数? 介绍过引用和指针的相互转换, 那对于对象而言,

能否用对象引用代替对象指针呢? 接下来就介绍 如何用引用代替指针.

代码: ConstObjectPointer.h 虽然解决了创建副本的问题,

从而减少了对复制构造函数和析构函数的调用.它使用指向const对象的const指针,

因此也解决了在函数中可能修改对象的问题.

这里有个小问题,为什么要用const指针呢? 可能是为了防止指针被修改,永远指向该对象.

比如删除指针再分配新指针指向.

而在构造函数分配的内存中这么做,无意会使程序发生极其危险的后果.所以用const指针.

然而,这有些繁琐,因为传递给函数的是指向对象的指针.

由于对象不可能为空,如果传递引用而不是指针,则在函数中处理起来将更方便.

 请查看参考代码: ReferenceInsteadPointer.h

 

==========================================

Main.cpp :

#include <iostream>
using namespace std;

#include “NewAndDeleteObject.h”
#include “ReferenceEfficiency.h”
#include “ConstObjectPointer.h”
#include “ReferenceInsteadPointer.h”

void main()
{
           NewAndDeleteObject();
           cout<<endl;
           ReferenceEfficiency();
           cout<<endl;
           ConstObjectPointer();
           cout<<endl;
           ReferenceInsteadPointer();
           cout<<endl;

}

NewAndDeleteObject.h :

class Cat
{
private:
           int itsAge;

public:
          Cat(); //默认构造函数
          ~Cat(); //析构函数
};

Cat::Cat()
{
          cout<<“Call Constructor.”<<endl;
          itsAge=5;
}

Cat::~Cat()
{
          cout<<“Call Destructor.”<<endl;
}

void NewAndDeleteObject()
{
          cout<<“New A Cat Frisky”<<endl;
          Cat Frisky;//类中的对象被创建,
          cout<<“Cat *pCat = new Cat;”<<endl;
          Cat *pCat = new Cat;//类中新对象被创建,再次调用构造函数
          cout<<“Delect Pointer pCat.”<<endl;
          delete pCat;//删除指针,导致对象被删除,所以pCat指向的Cat对象内存被释放,调用析构函数
          cout<<“Delected.”<<endl;
}
//最后程序结束,需要释放构造函数的内存和资源,
//Frisky将被释放,所以再次调用析构函数.结束程序.

 

ReferenceEfficiency.h :

/*这个例子比较复杂,但是看明白之后,就会对引用与构造函数有更深刻的体会*/

class Dog
{
public:
           Dog();//创建构造函数
           Dog(Dog&);//创建复制构造函数
           ~Dog();//创建析构函数
};

Dog::Dog()
{
           cout<<“Call Constructor.”<<endl;//告知调用构造函数
}

Dog::Dog(Dog &)
{
           cout<<“Call Copy of Constructor.”<<endl;//告知调用复制构造函数
}

Dog::~Dog()
{
           cout<<“Call Destructor.”<<endl;//告知调用析构函数
}

Dog Funtion1(Dog theDog);
Dog *Funtion2(Dog *theDog);

void ReferenceEfficiency()
{
           cout<<“New a object named Wangwang”<<endl;
           Dog Wangwang;//创建Wangwang对象
           cout<<“Call the 1st function.”<<endl;
           Funtion1(Wangwang);
           cout<<“Call the 2nd function.”<<endl;
           Funtion2(&Wangwang);
           //cout<<&Wangwang<<endl;
}

Dog Funtion1(Dog theDog)
{
           cout<<“1st function is called.”<<endl;
           return theDog;
}

Dog *Funtion2(Dog *theDog)//对象指针直接指向对象引用
{
           cout<<“2nd function is called.”<<endl;
           return theDog;
}
/*
此程序创建了一个Dog对象,然后调用两个函数.
第一个函数按值接受一个Cat对象,然后按值返回它.
第二个函数接受一个对象指针而不是对象本身作为参数.
*/

 代码中,我注释掉了这个//cout<<&Wangwang<<endl;

 如果未被注释掉,这会出现这样的结果:

这是按引用传递, 而不是按值传递.所以没有多次调用复制构造函数.

  

 ConstObjectPointer.h :

class dog
{
private:
           int itsWeight;
public:
           dog();
           dog(dog&);//复制构造函数
           ~dog();
 
           void SetWeight(int Weight){itsWeight=Weight;}//类内联函数(inline)
           int GetWeight() const {return itsWeight;}//类内联函数(inline)和const(保护itsWeight不被修改)
};

dog::dog()
{
           cout<<“Call Constructor.”<<endl;//调用构造函数
           itsWeight=5;//初始化itsWeight值为5
}

dog::dog(dog &)
{
           cout<<“Call Copy Of Constructor.”<<endl;//调用复制构造函数
}

dog::~dog()
{
           cout<<“Call Destructor.”<<endl;//调用析构函数
}

const dog *const Function2(const dog * const thedog);
//dog *const Function2( dog * const thedog);

void ConstObjectPointer()
{
           cout<<“New a object of dog.”<<endl;
           dog Lucky;
           cout<<“Lucky is “<<Lucky.GetWeight()<<” kg.”<<endl;
           int Weight=6;//重新定义Weight变量;
           Lucky.SetWeight(Weight);
           cout<<“Lucky is “<<Lucky.GetWeight()<<” kg.”<<endl;
           cout<<“Call Function2().”<<endl;
           Function2(&Lucky);
           cout<<“Lucky is “<<Lucky.GetWeight()<<” kg.”<<endl;
}

const dog *const Function2(const dog * const thedog)
//dog *const Function2( dog * const thedog)
{
           cout<<“*Function2() was called.”<<endl;
           cout<<“*Now Lucky is “<<thedog->GetWeight()<<” kg.”<<endl;
           //thedog->SetWeight(80); 
           //这里试图将对象用存取器SetWeight函数赋值,但是由于是const的,所以不能修改.
           return thedog;
}

如果用非const对象指针的话,会出现什么情况?

 ReferenceInsteadPointer.h :

class cat
{
private:
            int itsWeight;
public:
            cat();
            cat(cat&);
            ~cat();

            void SetWeight(int Weight){itsWeight=Weight;}
            int GetWeight(){return itsWeight;}
};

cat::cat()
{
            cout<<“Call Constructor.”<<endl;
            itsWeight=2;
}

cat::cat(cat&)
{
            cout<<“Call Copy of Constructor.”<<endl;
}

cat::~cat()
{
            cout<<“Call Destructor.”<<endl;
}

/*const*/ cat &Function2 (/*const*/ cat &thecat);
//这里注掉的原因是为了验证对象引用对对象的修改功能,本应为const,防止对象被随意改动

void ReferenceInsteadPointer()
{
            cout<<“New a object of cat.”<<endl;
            cat mimi;
            cout<<“Mimi is “<<mimi.GetWeight()<<” kg.”<<endl;
            mimi.SetWeight(3);
            cout<<“Mimi is “<<mimi.GetWeight()<<” kg.”<<endl;
            cout<<“Call Function2().”<<endl;
            Function2(mimi);
            cout<<“Mimi is “<<mimi.GetWeight()<<” kg.”<<endl;
}

/*const*/ cat &Function2 (/*const*/ cat &thecat)
//这里注掉的原因是为了验证对象引用对对象的修改功能,本应为const,防止对象被随意改动
{
            cout<<“Function2 was called.”<<endl;
            cout<<“Mimi is “<<thecat.GetWeight()<<” kg.”<<endl;
            thecat.SetWeight(10);//因为不是const对象,所以这里itsWeight值被修改.
            return thecat;
}
/*
改程序的变化是,Function2()接受一个指向const对象的引用作为参数,并返回一个这样的引用.
同样,使用引用比使用指针更简单,但在内存节省和效率方面与指针相同,同时可以使用const来提供安全.
*/

=========================================================================

最后是所有代码一起运行以后的截图:

*******************************************

PS:这一节学的相当累, 写的也相当繁琐.花了近1天的时间来写这篇post,坐在电脑前就没动过.

不过还好,学到了很多,而且也终于写完了.

太不容易了.

10.5 合理使用类(内联函数)

Posted: March 27, 2011 in C++

ClassUsing.h :

/*
大多数程序员使用的方法是将类放入头文件里.该头文件的扩展名为.h,.hp, .hpp.

例如,将Cat类的声明放在一个名为Cat.h的文件中, 而将类方法的定义放在Cat.cpp文件中.
然后,在Cat.cpp将其关联,开头加入如下代码:

#include “Cat.h” //就好像输入了该文件内容一样

那为什么要将它们分开? 大多数情况下,类的客户并不关心实现细节.
只要阅读头文件,就可以知道需要的信息了,他们可以忽略实现文件.

之前说过 内联函数 ,类方法也可以作为内联的.只需要在返回类型前加上关键字inline.
例如, GetAge()函数的内联如下:

inline int Cat::GetWeight()
{
         return itsWeight;
}

也可以将函数的定义放到类生命中,这样函数将自动成为内联的.
例如:

class Cat
{
public:
         void SetWeight(int Weight);
         int GetWeight(){return itsWeight;} //inline
};

也可以这样写:

class Cat
{
public:
         void SetWeight(int Weight);

         int GetWeight() const  //inline
         {
                  return itsWeight;
         }
};

*/

class Cat
{
private:
         int itsAge;

public:
         void SetAge(int age){itsAge=age;}
         int GetAge(){return itsAge;} //inline
};

====================================

Cat.cpp :

/*实现文件*/
#include “ClassUsing.h”
#include <iostream>

using namespace std;

void main()
{
         Cat Frisky;
         Frisky.SetAge(5);
         cout<<“Cat is “<<Frisky.GetAge()<<” years old.”<<endl;
}

定义常量已经在之前的post里面介绍过了,

请参阅: http://wp.me/p14oGQ-6g

使用 const 指针 :

声明指针时,可以在类型前或后使用关键字const,也可在这两个位置都使用.

以下都是合法的声明:

const int *p1;

int * const p2;

const int  const *p3;

然而这些声明的含义不同:

~ p1是一个指向整形常量的指针.它的指向是不能修改的.

~p2是一个指向整形的常量指针.他只想得知可以修改,但p2不能指向其他变量.

~p3是一个指向整形常量的常量指针.它指向的值不能修改,且这个指针也不能指向其他变量.

理解这些的技巧在于:

查看关键字const右边来确定什么被声明为常量.

如果该关键字的右边是类型,则值是常量.

如果该关键字的右边是指针变量,这指针本身是常量.

eg:

const int *p1; //the int pointed to is constant

int *const p2; //p2 is constant, it can’t point to anything else

如果对象不应被修改,则按引用传递它是应用const进行保护.

务必将指针设置为空,而不要让它未被初始化(迷途,悬浮指针).

不要使用已被删除的指针, 不要将指针删除多次.

Q: 既然const对象限制了对其的修改,为什么要声明这样的对象呢?

A: 因为想让编译器帮您查找错误. 一种很难发现的严重错误是: 函数以对调用函数来说不明显的方式修改对象,

     将对象声明为const可以防止这种被修改.

 Const成员函数 :

 如果将类方法声明为const, 必须保证该方法不会修改任何成员的值.

将类方法声明为const:

void SomeFunction() const;

 这生命了一个名为SomeFunction()的const成员函数,他不接受热河参数,返回类型为void.

由于它被声明为const, 因此不会修改其所属类的任何数据成员.

通常使用修饰符const将只读取得存取器函数声明为const函数, 前面的Cat类有两个存取器函数:

void SetAge(int anAge);

int GetAge();

函数SetAge()不能是const的, 因为他修改成员变量itsAge的值; 而GetAge()应该是const的, 因为它不能修改类的任何成员.

GetAge()只返回成员变量itsAge的当前值. 因此这些函数的生命应该写成这样:

void SetAge(int anAge);

int GetAge() const;

如果将一个函数声明为const, 而该函数的实现通过修改某个成员变量而修改了对象, 编译器将视为错误.

例如, 如果将前面的GetAge()声明为const, 而记录询问Cat年龄的次数, 将产生编译错误,这是因为调用了该方法将修改Cat对象.

一种良好的习惯是,尽可能将方法声明为const的. 让编译器捕获错误, 而不至于等到程序运行时, 才出现bug.

Q: 既然在const函数对类进行了修改会导致编译错误, 为什么不能省略掉const以避免错误呢?

A: 如果成员函数在逻辑上不应该修改类, 则通过使用const, 可让编一起帮助发现一些错误.

     例如, GetAge()函数可能没有理由回去修改Cat类, 但是实现中可能有下面这行代码:

     if(itsAge = 100) cout<<” U R 100 YEARS OLD”;

    如果就爱那个GetAge()声明为const的, 将导致这段代码被视为错误的. 由于你的本意是判断 itsAge 是否等于100, 但不小心将100赋给了itsAge. 由于这种赋值修改了类, 而声明中又指出该方法不会修改类, 因此编译器能够发现这种错误.

    这种错误仅仅通过浏览代码, 很难发现. 人们常常只能看到预期的东西. 更重要的是, 程序可能显示一切正常, 但itsAge却被设置为一个错误的值, 这迟早会导致问题.

以上分别介绍了const用于定量,指针和成员函数的三种用法.

================================================

还有一种const用法: 传递const指针

请参阅: http://wp.me/p14oGQ-83

10.3 构造函数‖析构函数

Posted: March 27, 2011 in C++

/*
初始化变量,即 int a=1; 变量a被初始化为1.
那么如何才能初始化 类(class) 中的 成员函数 呢?
就需要用到 构造函数(constructor) 和 析构函数(destructor).

构造函数可以根据需要接受参数, 但他不能有返回值(void也不能),
构造函数是一个与类同名的类方法.声明构造函数后,还应声明析构函数.

构造函数创建并初始化类对象,
而析构函数在对象被销毁后完成清理工作并释放分配的资源和内存.
析构函数与类同名,但在前面加上了一个 ~ .

析构函数没有参数,也没有返回值. 如: ~Cat();

如果没有创建构造函数和析构函数,编译器提供一个默认的构造函数与析构函数,且不接受任何参数.
如果希望它们执行一些操作,必须创建自己的默认构造函数或析构函数.

那为什么要创建构造函数呢?
它可以初始化成员变量.

如果生命了一个构造函数,就要再生命析构函数.

比如,使用一个非默认构造函数来初始化Cat对象,将其年龄设置为您提供的年龄.
*/

#include <iostream>

using namespace std;

class Cat
{
private:
          int itsAge;

public:
          Cat(int initialAge);//初始化Cat的一个参数
          ~Cat();//释放构造函数的资源和内存
          int GetAge();
          void SetAge(int age);
};

Cat::Cat(int initialAge)
{
          itsAge=initialAge;//将初始化的值付给Cat itsAge
}

Cat::~Cat(){}//析构函数,无任何操作

int Cat::GetAge()
{
          return itsAge;
}

void Cat::SetAge(int age)
{
          itsAge=age;
}

void main()
{
          Cat Frisky(5); //初始化其值为5.
          cout<<“The Frisky is “<<Frisky.GetAge()<<endl;//在没给使用存取器函数之前已通过构造函数赋值(即初始化成员变量)
          Frisky.SetAge(7);
          cout<<“The brother of Frisky is “<<Frisky.GetAge()<<endl;
}

/*
如果构造函数根本不接受参数(即:它是默认构造函数),应去掉括号:
Cat Frisky;
这行代码,将被解释为调用默认构造函数,没有提供任何参数,因此将括号省略.

当然构造函数本身也可接受多个参数,比如
Cat(int InitialAge, int InitialWeight );~Cat();

Cat(5,100);
*/

10.2 存取器方法(Accessor Method)

Posted: March 26, 2011 in C++

/*
有没有什么方法可以 设置数据成员为私有,然后在其他函数中 修改呢?
答案是:有的,那就是创建 存取器方法 或 存储器函数.即AccessorMethod.

为什么不直接在公有成员变量,即public中设置使用,
而是要多设置一个私有成员变量,即private成员变量,
然后通过改变公有成员变量来改变其在私有成员变量中的值呢?

答案是:
存取器函数能够将 存储细节 与 数据使用细节 分开.
通过使用存取器函数,以后修改数据的存储方式时,不必重新编写使用这些数据的函数.
这种技术使得程序更容易维护,它延长了代码的生命周期,因为设计的变化不会导致程序作废.
同时存取器函数也包含一些其他的逻辑方法.
*/

#include <iostream>

using namespace std;

class Cat
{
public:
            int GetAge();//声明公有存取器函数
            void SetAge(int Age);//声明公有存取器函数
 
            int GetWeight();//声明公有存取器函数
            void SetWeight(int Weight);//声明公有存取器函数

            void Eat();

private:
            int ItsAge;
            int ItsWeight;
};

void Cat::SetAge(int Age)
{
            ItsAge=Age;//将Age赋值个私有成员变量ItsAge
}

int Cat::GetAge()//调取私有成员变量ItsAge的值
{
            return ItsAge;//返回ItsAge的值
}

void Cat::SetWeight(int Weight)//同理
{
            ItsWeight=Weight;
}

int Cat::GetWeight()
{
            return ItsWeight;
}

void Cat::Eat()
{
            cout<<“I can eat.”<<endl;
}

void main()
{
            Cat Frisky;
            Frisky.SetAge(2);
            /*main无法直接访问ItsAge但是可以访问公有成员函数,
            当然也就可以访问SetAge()和GetAge(),
            而在class Cat里又包含SetAge()和GetAge(),
            所以也就可以访问私有成员变量ItsAge.
            从而为私有ItsAge赋值.*/
 
            Frisky.SetWeight(100);//同理
            Frisky.Eat();
            cout<<“I am “<<Frisky.GetAge()<<” years old.”<<endl;
            cout<<“And I am “<<Frisky.GetWeight()<<” g.”<<endl;
}
//这里达到了通过访问公有存取器函数来给私有成员变量赋值的作用.
//更好地保护了私有数据不被随意修改.

Reference Previous Post: (English)

http://wp.me/p14oGQ-5W

http://wp.me/p14oGQ-5Y

10.1 声明类

Posted: March 26, 2011 in C++

/*
这里进入了面向对象编程.
说面向对象,其实很好理解,就是一个东西,他有什么,你就可以用什么.

比如:有辆车,车就是一个对象.他有什么?轮子,玻璃,引擎等等.
那可以用它们做什么?轮子可以跑,玻璃可以挡雨,引擎可以加速.
你要做的就是想着这个车,来造出你的有轮子,玻璃和引擎的车.
这就是面向对象编程.

首先,要声明一个类,就是说你要造的大概是个什么东西,比如这里的车.
然后你要说,这个车都有什么特征.
比如有轮子,玻璃,引擎.那轮子,玻璃,引擎大概有多大?
知道了这些,就可以声明一个类了.
声明以后,你放了什么特征进去,就只能用你声明过的特征和功能.
比如你想开车载GPS,但是如果你没有放入车的特征,是不能使用的.
你只能使用轮子,玻璃和引擎.除非你声明加多GPS功能.
如果要用某一功能的话,还需要加多开启功能.比如你要声明”打开GPS”.
如果不声明,只有GPS也只能成为摆设.
但是这里又有一个问题,就是你是要造私家车,还是要造辆公用车.
即:private和public.如果没有预先声明,就会默认你要造私家车,即private.
对你的隐私的一种保护.但问题是,其他人都不能随便使用你的私家车,
更进一步,更不能随便使用你的车的功能.
所以,如果你想让大家都能来使用你造的车,就把它定义为公用车.
这样大家就可以方便的使用了.

声明以后,你也可以给你的不同车取不同的名字,如BMW,benz等等.
这样,所有的BMW或者benz就都有轮子,玻璃,引擎或者GPS的特征了.
然后,你在放入”引擎加速”,”开启GPS”等的功能.
也就是说你声明了类(车)之后,以及成员函数(开启GPS)和成员变量(GPS).

在其他函数中你可以定义对象,,如定义了对象(BMW).
对象可以定义多个,Benz,Honda.它们同样具有上述特征和功能.

*******************************************

class 类名
{
public:
            类型 变量名;
            返回类型 函数名();
private:
            类型 变量名;
            返回类型 函数名();
};

*************最后的分号不能忘**************
void main()
{
             类名 对象;
             对象.变量名;
             对象.函数名();
}

*****************点不能忘******************
*/

#include <iostream>

using namespace std;

class Cat //这里声明Cat类
{
public://声明为公有,这样其他函数就可以访问这个类了,否则是无法访问的,默认是私有
            int Age;//Cat的特征包括年龄和体重
            int Weight;
            void Eat();//Cat可以吃东西
};

void main()
{
            Cat Frisky;//声明一只叫Frisky的Cat,当然声明多少只都可以.
            Frisky.Age=2;//Frisky也有年龄和重量
            Frisky.Weight=100;
            Frisky.Eat();//Frisky可以吃东西
            cout<<“I am “<<Frisky.Age<<” years old.”<<endl;
            cout<<“And I am “<<Frisky.Weight<<” g.”<<endl;
}
void Cat::Eat()
{
             cout<<“I can eat.”<<endl;
}
//这样一个简单类就声明完成了.