第十一天(对象和类)

      应该有一个星期没写了吧,原因之一是被数据结构实验,需要编程,费时多。以后多抽时间写吧。希望编辑完并发表没有过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 I
Student 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 I
const Student top = s2.com(s1); //Form II
top.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:people
	double area;	//Unit:square kilometer
	double 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();

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值