类的基本思想时数据抽象和封装,数据是一种依赖接口和实现所能执行的操作,封装类的接口和实现分离。隐藏了实现细节,类的用户只能使用接口但无法访问具体实现。 创建类时,使用#ifndef可以防止多次包含同一个文件。
一,类的基础
类的设计尽可能将共有接口与实现细节分开。类的声明类似结构声明,可以包括数据成员和函数成员,声明有是由部分,私有部分只能禅院函数进行访问,共有部分可以使用类的对象程序直接访问。
1,类的声明结构
class 类名{
private:
私有数据成员和成员函数声明
public:
公有数据成员和成员函数的声明
}
类的实现建议与声明同名,直接定义在类的声明中的函数是内联函数。 例如:
#ifndef STOCK_H
#define STOCK_H
#include<string>
//类的声明
class Stock{
private:
long shares;
double share_val;
double total_val;
void set_tot();
public:
//声明成员函数
void acquire(const long n,double pr);
void buy(long num,double price);
void sell(long num,double price);
void update(double price);
void show();
};
#endif // STOCK_H
共有部分的内存构成了设计的抽象部分,将数据封装到私有部分可以保护数据的完整性。
2,类的定义
Stock::Stock(const string & company,long shares,double share_val){
}
使用时
Stock food = Stock("Word Cabbage",250,1.25);
或
Stock garment("Furry Mason",50,2.5);
类的定义就是对象,使用时必须添加类的头文件。 公有成员可以被所有函数访问,私有成员只能被自己的成员函数访问。
3,构造函数
未提供显示初始值时,用来创建对象的构造函数,默认构造函数没有参数。 当程序创建未显示初始化的类对象时,会调用默认构造函数。 例如:
struct Sales_data
{
Sales_data() = default;//默认构造函数
Sales_data(const string& s) :bookNo(s) {};//构造函数
Sales_data(const string& s, unsigned n, double p):bookNo(s),units_sold(n),revenue(p*n) {}//多参构造函数
Sales_data(std::istream&);//构造函数
string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
double avg_price() const;
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
int main() {
Sales_data total;
}
4,析构函数
用构造函数创建对象后,程序复杂更新该对象,知道其过期时会自动调用析构函数,析构函数主要用来完成清理工作。 析构函数是在函数名之前新增一个“~”符号
Stock::~Stock(){
}
5、this指针
代指当前类的对象,指向当前调用函数的对象
const Simple &Simple::top(const Simple&a )const{
…
return *this
}
*this 表示当前对象
6、运算符重载
使对象能用运算符操作 例如a1=a2+a3; 限制 1)不是所有的运算符都能重载 2)重载不能改变运算符的优先级和结合性 3)重载不能改变运算符的操作数个数 4)不能创建新的运算符 重载赋值运算符,函数名为operator =l 例如
A operator +(const A&a )const
7、友元
永许访问私有成员,在类声明中用friend创建友元,友元的声明可以在类的声明任意地方,通常放在最后或最前面,主要用于运算符重载
class{
friend int fun(double);
}
如果对象是通过new创建的,则它将驻留在栈内存和自由内存区域中,当使用delete释放内存时,其析构函数将自动被调用。 每个类只有一个析构函数,析构函数没有返回类型,有没有参数。
二,类的访问与封装
1,访问修饰符
在C++中也有对应的访问权限修饰符 1)public:成员在整个程序内可被访问 2)private:成员可以被类的成员函数访问,但不能被使用该类的代码访问,private部分封装了类的实现细节。 2)protected:子类可访问 例如:
class Student{
private:
int age;
public:
setAge(int age);
}
使用访问修饰符时个数限制,只要根据要求放到需要的访问区间内就可以正常使用。 使用class和struct关键字的区别,struct的成员默认是public访问区间的,class默认是private类型的。
2,可变的数据成员
为类的成员添加mutable修饰后,便可以在const成员函数内修改类的数据成员。 例如:
class Student{
private:
int height;
public:
void changeProperty()const ;
}
void Student::changeProperty()const
{
height = 30;
}
在类中声明了一个const的成员函数,然后再定义中修改类的属性时,编译器会直接报错,如果把height使用mutable进行修饰,则可以进行修改。
三,构造函数
在C++中对象的使用,是先定义,在赋值 例如:
string foo = "Hello World!";//定义并初始化
string bar; //默认初始化成空string对象
bar = "Hello World!"; //为bar赋一个新值
1,构造函数的参数 在构造函数中如果成员是const或者应用的话,必须将其初始化。 例:
class ConstRef
{
public:
ConstRef(int ii) :i(ii), ci(ii), ri(i) {};
private:
int i;
const int ci;
int& ri;
};
如果成员是const,引用,或者属于某种未提供默认构造函数的类类型,我们 必须通过构造函数初始值列表为这些成员提供初值。
2,默认实参和构造函数 在构造函数中可以提供默认的实参 例如:
class Student{
public:
Student(int num = 20):age(num){}
private:
int age;
}
注:如果成员属性的初始化赋值有互相依赖,则在构造函数中必须按照一定的顺序进行初始化赋值。
3,委托构造函数 使用所属类的其他构造函数执行自身初始化的过程。 例如:
class Student
{
public:
Student(int l1, int l2, int l3) :age(l1), height(l2), weight(l3) {}
Student(int l1, int l2) :Student(l1, l2, 0) {}
Student(int l1) :Student(l1, 0, 0) {}
~Student();
private:
int age;
int height;
int weight;
};
四,类的静态成员
把类的成员声明成静态成员后,它就会变成只和类有关联,和类的每个对象无关联。
1,静态成员的声明
在成员的声明之前添加static进行修饰,类的静态成员存在于任何对象之外,对象中不能包含任何于静态成员有关的数据。 例如:
#include<istream>
using namespace std;
class Account
{
public:
void calculate() { amount += amount * interestRate; }
static double rate() { return interestRate; }
static void rate(double);
private:
std::string owner;
double amount;
static double interestRate;
static double initRate();
};
静态成员函数也不与任何对象绑定在一起,他们不包含this指针。 使用静态成员函数时,直接使用“类名::成员函数”的方式进行调用。
2,定义静态成员
在静态成员定义时,其static关键字只能在头文件中进行声明,在定义时不能重复static关键字 例如:
void Account::rate(double newRate){
interestRate = newRate;
}
静态成员不能在类的内部初始化,只能在类的外部定义和初始化每一个静态成员。静态成员一旦被定义,将一直存在于程序的整个生命周期中。
3,静态成员的类内初始化
可以为静态成员提供const整型类型的类内初始化,但需要静态成员必须是字面值常量类型的constexpr,初始值必须是常量表达式。 因为这些成员本身就是常量表达式,所以他们能用在所有适合于常量表达式的地方。 例如:
class Account
{
public:
void calculate() { amount += amount * interestRate; }
static double rate() { return interestRate; }
static void rate(double);
private:
std::string owner;
double amount;
static constexpr int period = 30;//是一个常量表达式
};
注: 静态成员可以是它所属的类类型,而非静态数据成员则受到限制,只能声明成它所属类的指针和引用。
class Account{
private:
static Account mm1;//静态成员可以是不完全类型
Account* pr;
Account mm;//编译器报错,数据成员必须是完全类型。
}
静态成员可以作为默认的实参,而普通成员则不可以。
五,类的继承
在一个或多个已有类的基础上扩展属性和方法,形成一个强大的类。 基类:已有的类 派生类:扩展后的类 这样可以实现代码重用,也可以重用不公开的类 继承分为三种 1)公有继承,public修饰 2)私有继承,private 修饰 3)保护继承,procted修饰
1、重定义基类函数
重新定义实现基类的函数,添加自己扩展的实现。最后要添加基类的调用。
2、公有继承与多态
在基类中添加虚函数,当基类指针指向派生类对象,并对指针调用虚函数时,会到派生类中去寻找同原型的函数并执行,如果不存在,则调用基类的函数。
3、protected 保护的成员
只能被自己的派生类访问,可以提高派生类的效率。
4、多继承
一个类继承多个类,会出现二义性问题 解决方法 1)使用作用域运算符 2)重新封装调用基类 3)使用虚基类 例如:
class Parent{
private:
int age;
public:
int getAge();
}
class Child:Parent{
public:
private:
}
|