应该有一个星期没写了吧,原因之一是被数据结构实验,需要编程,费时多。以后多抽时间写吧。希望编辑完并发表没有过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();
}