类是结构(struct)的一种,默认情况下,它的内部外界是无法访问,而C++中的struct是默认是公开的, 通常,C ++的struct只包含普通的旧数据(plain old data),而在C ++中,类(class)主要用于组织数据结构的工具,类有两个核心概念:数据隐藏和封装
C ++允许在struct中定义成员函数(在本章中介绍),从而扩展了C的struct和概念。 成员函数是只能与这些数据类型的对象一起使用或在这些数据类型范围内的函数。 其中一些成员函数的特殊之处在于,当对象初始化的时候(所谓的构造函数)或结束其生命(所谓的析构函数)时,它们总是(通常是自动地)被调用。 本文将会构建一个Person类为🌰,深入浅出地去认识C++的面向对象思想。
在开始之前,需求区分类接口以及的它的实现。
- 类是可以松散地定义为"一组数据以及操作这些数据的函数"
- 类接口是定义该类的对象的定义,可以理解和函数声明是同一级别对待的。通常,定义会告知C++编译预留相应的内存,例如,在定义int变量的时候,编译器确保在存储便来唔值的最终程序中保留一些内存。虽然类接口是一个定义,但是一旦处理完类定义,编译器就会回收相应的内存。
类接口的定义遵循一个规则:“在C++中,一个类接口的实体只能定义一次,由于类定义并不意味着保留内存,因此叫类接口更容易区分.”类接口,通常包含在类的头文件中,比如person.hh
#include <string>
class Person
{
std::string d_name;
std::string d_address;
std::string d_contact;
size_t d_age;
public:
Person(){};
Person(
std::string const &pname,
std::string const &paddr,
size_t const &age);
void setName(std::string const &pname);
void setAddress(std::string const &paddr);
void setContact(std::string const &phone);
void setAge(size_t const &age);
const std::string name() const;
const std::string address() const;
const std::string contact() const;
const size_t age() const;
};
在接口中声明的成员函数必须被现实,例如在源文件person.cpp中,这些实现成为对成员函数(原型)的定义。
除了成员函数之外,类还包括定义由这些成员函数操作的数据,这些数据成为数据成员,例如Person类中的pname,address,contact,和age,通常这些数据成员应该被private关键字修饰。表示只有Person类才能访问这些数据成员。由于类默认实用private关键字,因为数据成员位于Person类接口的顶部.
class 和struct的比较
- class:隐藏了他们的数据,使其不被外界访问(这被称为数据隐藏)并提供成员函数来定义外部世界和类的数据成员之间的通信。
- struct:聚合数据,这些数据都是可以自由访问。
编写类接口的建议
根据《大规模C ++软件设计/Large-Scale C++ Software Design》一书中建议
- 所有数据成员都具有私有访问权限,并且位于类接口的顶部。
- 所有数据成员都以d_为前缀,后跟一个表明其含义的名称。
- 非私有数据成员确实存在,应该用关键字public显式修饰。
- 操纵器的成员函数 按照惯例,操纵器以set开头。 例如,setName。
- 对于访问器,仍然经常遇到get-prefix,例如getName。 但是,遵循Qt(请参阅http://www.trolltech.com)图形用户界面工具包提供的约定,现在不推荐使用get前缀。 因此,不应该定义成员getAddress,而应该简单地命名为address。
- 通常(存在例外)类的公共成员函数首先列在类的数据成员之后。将它们罗列在接口中是一个常规问题。 成员函数默认是public修饰的成员函数的,如有不对外公开的成员函数应该显式实用private修饰。
编写风格约定通常需要很长时间才能形成写程序的习惯。 这仅仅是一些C++的大牛给的一些建议,读者是否遵循是你的个人自由。
构造函数
C ++的类包含两个特殊类别的成员函数,这些类对于正确使用类是必不可少的。
- 构造函数:对类实例内部的数据成员进行初始化。
- 析构函数:主要任务是在对象超出范围时将对象分配的内存返回到公共池。
构造函数的名称与其类名相同。 不指定返回值,甚至不指定void。 例如,类Person可以定义构造函数Person :: Person()。 C ++运行时系统确保在定义类的变量时调用类的构造函数。C++允许可以定义没有任何构造函数的类。 在这种情况下,编译器定义了在定义该类的对象时调用的默认构造函数。 在这种情况下实际发生的事情取决于该类定义的数据成员。
对象可以全局定义或局部定义,然而在C++中大部分对象是在局部定义的,并且几乎不需要全局定义的对象。在一个函数内部定义一个局部的对象,每次调用函数时都会调用该对象的构造函数,在对象的定义的地方该对象的构造函数就会被激活(换言之,对象可以隐式地定义为表达式中的变量)。在外界和类内部数据成员的所有通信都是由成员函数进行交互的。成员函数可以接受参数,或者可以检索类内部的数据成员。
- 仅返回存储在类实例(对象)内的值,而不允许调用者修改该值的成员函数称为访问器,访问器已被被修饰关键字const,因此也称为const成员函数;
- 仅接受参数用于修改类实例内存储的值,称为操纵器.
下面对Person类接口的完整实现代码
#include "../header/person.hh"
#include <iostream>
using namespace std;
Person::Person(string const &pname, string const &paddr, size_t const &age)
{
d_address = paddr;
d_name = pname;
d_age = age;
}
void Person::setName(std::string const &pname)
{
d_name = pname;
};
void Person::setAddress(std::string const &paddr)
{
d_address = paddr;
};
void Person::setContact(std::string const &phone)
{
d_contact = phone;
};
void Person::setAge(size_t const &age)
{
d_age = age;
};
const string Person::name() const
{
return d_name;
};
string const Person::address() const
{
return d_address;
};
const string Person::contact() const
{
return d_contact;
};
const size_t Person::age() const
{
return d_age;
};
下面是一个完整的Person实例的调用,请注意函数display_person的参数列表中的&运算符。 仅将对现有Person对象的引用传递给函数,而不是Person对象的一个拷贝。 display_person不修改其参数的事实从参数声明为const的事实可以看出。
void display_person(Person const &p)
{
cout << "姓名:" << p.name() << endl;
cout << "地址:" << p.address() << endl;
cout << "电话:" << p.contact() << endl;
cout << "年龄:" << p.age() << endl;
};
int main(int argc, char const *argv[])
{
Person sone;
sone.setName("Billy");
sone.setAddress("dong guan city load 13e");
sone.setContact("emai:test@egg.com");
sone.setAge(19);
display_person(sone);
return 0;
}
网友评论