第十一天(对象和类)

来源:互联网 发布:不用网络的枪战游戏 编辑:程序博客网 时间:2024/06/07 16:23

      应该有一个星期没写了吧,原因之一是被数据结构实验,需要编程,费时多。以后多抽时间写吧。希望编辑完并发表没有过12点。


2011-10-29(Objects and Classes)
1、类的定义格式一般如下:

class Student{private:    char name[20];    void addNum();public:    void setName(char*);    char* getName();    void show();};
注意最后的分号。这个定义和结构体相像,只是类中,成员默认的访问控制是private而结构体是public,但为了加强数据隐藏的概念,通常都显式地使用private。通常的做法是,将类的定义写在头文件中,再用另一个cpp文件定义类中声明的成员函数。定义函数时,有两点要了解:
①定义成员函数时要使用作用域操作符(::)来表示函数所属的类;
②类方法可以访问类的private
**首先要提得是作用域的概念,即是可访问的地方。如,静态内部链接性的变量在整个源文件文件都是可访问的,就说作用域是整个源文件。类的作用域,即是类成员函数体范围的并集。由于函数中不能定义函数,所以定义函数是一般不在类作用域中,要加作用于操作符来定义函数:
void Student::setName(char* n){    strncpy_s(name,n,19);}
当然,在类作用域中,不必使用::操作符:
void Student::show(){    cout << "Name: " << getName() << endl;}
函数strncpy_s与strncpy功能一样,不过微软认为后者会有危险,所以改写了更安全的。这个函数的功能是,如果n的字符数小于等于第三个参数19,不足的用NULL补足,大于则自动截取19个字符赋给name。
**成员函数可以访问类的私有成员,所以成员函数是类对外的一个接口:
                char* Student::getName(){ return name; }
当然也有私有函数的情况,但这种情况中,类作用域外不能访问,一般用作内部数据的处理。比如在姓名后面加个学号,在类作用域中可以调用这个函数,而不必每次需要这个操作时都要编写代码实现。听起来很像内联函数,实际上,它就是内联函数,定义位于类声明的函数都会自动成为内联函数,如果在类中没有定义函数体,可以在类的声明后面定义(前面说过,内联函数可以应在头文件中定义)
               inline void Student::addNum(){ std::cout << name << 5 << std::endl; }
当然不能在类中定义了的同时再用inline定义。
2、构造函数(Constructor)。
I、定义。与java类似(或言:java与C++类似),C++有构造函数对类成员初始化,不过与java不同的是,C++将构造函数的声明和定义分开了,即:
//... ...public:    Student(char* );//... ...Student::Student(char* m_name){    strncpy_s(name, m_name, 19);}
**规则也差不多:当且仅当没有显式定义构造,编译器自动添加默认构造函数。如果显式定义了构造函数,则不能在使用默认构造函数了,如在上面的Student的构造定义后,下面的写法是错误的:
                     Student stu; //invalid
如果想这样写,必须提供默认构造函数,因为在C++中有默认参数的概念,所以有下面两种方法定义默认构造函数:
                     Student();                     //default constructor
                     Student(char* m_name = "Tom"); //default constructor too

II、使用。三种方式:
Student s1 = Student("Karie");    //Form IStudent s2("Janne");              //Form II, the same as Student s2 = Student("Janne");Student* s3 = new Student("Ace"); //Form III
3、折构函数(Destructior)。顾名思义,是用作清理对象的,在用new分配对象内存的时候用delete来释放内存,如果不是用new生成对象,只需让编译器生成一个隐式的折构函数即可。
**折构函数没有参数,没有返回值,为了与构造函数加以区别,在类名前加上符号“~”,所以Student的折构函数原型必须是:
                              ~Student();
它的函数体一般在类外面定义。
**折构函数不需显式调用,编译器会自动调用的(有例外,后面再谈)。
4、类对象的一些操作。如果我们将折构函数定义并使用类Student如下:
Student::~Student(){    std::cout << "Bye, " << name << std::endl;}int main(){    Student s = Student("Tom");    s = Student("Karie");    s.show();    Student s1 = Student("Janne");    s = s1;    s.show();    s1.show();    return 0;}
将有如下输出:
                    Bye, Karie
                    Name: Karie
                    Name: Janne
                    Name: Janne
                    Bye, Janne
                    Bye, Janne

①可用构造函数对已有对象进行覆盖;
②可进行对象的复制;
③上面两中操作将产生临时对象,编译器会使用折构函数清理。
5、const成员函数。如果这样做:
                    const Student stu = Student("Tom");
                    s.show();

编译器将报错,因为show()函数保证不了对象不被修改,虽然我们知道这个函数是不会修改对象的,但是编译器不知道,所以要使用关键字const来做出保证:
                    void show() const;                     //function prototype
                    void Student::show()const{/*... ...*/} //function defined

这么声明后,show()将不能有一切不确定的可能改变对象的操作,比如,show()将不能调用非const成员函数。
6、this指针。this指针实际是所属类的const型成员指针(比如这里,this指针为:Student* const this),指向的是对象本身。比如如果比较两个对象名字字符串大小,并返回较大的,可以这样写:
Student Student::com(Student s)const{    if(strcmp(this->name,s.name) >= 0)return *this;    else return s;}
调用时,可以用如下两种形式:
const Student s1("Tom");const Student s2("Som");const Student top = s1.com(s2); //Form Iconst Student top = s2.com(s1); //Form IItop.show();
7、对象数组。如果我们这样写:
                    Student stu[4]; //implicit initialization
在程序没有显式地定义默认构造函数时,编译器会使用函数体为空的隐式默认构造函数对其初始化。也可以在声明数组是显式初始化:
Student stu[4] = {    Student("Tom"),    Student() //using default constructor    //... ...};

今天笔记好像有点短,编个习题答案:

**定义类Country,包括国家名、人口、领土面积。使用此类,从读入的一组国家数据中输出:①领土最大的国家;②人口最多的国家;③人口密度最大的国家

//flieName: Country.h#ifndef COUNN_H_#define COUNN_H_#include <string>class Country{private:std::string name;int population; //Unit:peopledouble area;//Unit:square kilometerdouble popuDensity()const{return population / area;}public:Country();Country(std::string, int, double);void show()const;Country areaCompare(const Country)const;Country popuCompare(const Country)const;Country pdCompare(const Country)const;};#endif

//filenName: Country.cpp#include <iostream>#include "Country.h"using namespace std;Country::Country(string na, int popu, double ar){name = na;population = popu;area = ar;}Country Country::areaCompare(const Country c)const{if(this->area > c.area)return *this;else return c;}Country Country::popuCompare(const Country c)const{if(this->population > c.population)return *this;else return c;}Country Country::pdCompare(const Country c)const{    double thisPD = this->popuDensity();    double guestPD = c.popuDensity();    if(thisPD > guestPD)return *this;    else  return c;}void Country::show()const{cout << "Conutry Name: " << name << endl;cout << "Population: " << population << endl;cout << "Territory Area: " << area << endl;cout << "Population Density: " << popuDensity() << endl;}
//fileName: Test.cpp#include <iostream>#include "Country.h"using namespace std;int main(){Country country[4] = {Country("China", 1356800000, 9640000),Country("Japan", 127767944, 377835),Country("Russian", 141000000, 17075500),Country("India", 1210200000,2980000)};Country top = country[0];for(int i = 0; i< 4; i++)top = top.areaCompare(country[i]);cout << "Country of Max-area:\n";top.show();cout << endl;for(int i = 0; i< 4; i++)top = top.popuCompare(country[i]);cout << "Country of Max-population:\n";top.show();cout << endl;for(int i = 0; i< 4; i++)top = top.pdCompare(country[i]);cout << "Country of Max-population-density:\n";top.show();}


原创粉丝点击