以C++ Primer Plus为参考书籍,自身归纳知识点,加深记忆。
对象和类
过程性编程与面向对象编程
过程性编程:首先考虑要遵循的步骤,然后考虑如何表示这些数据
面向对象编程:首先从用户的角度考虑对象,描述对象所需的数据以及描述用户与数据交互所需的操作,完成对接口的描述后,需要确定如何实现接口与数据储存,最后使用新的设计方案创建出程序。
对象和类
类
类是一种将抽象转化为用户定义类型的C++工具,将数据表示和数据操作的方法组合成一个整合包。
一般来说,类规范由两个部分组成:
①类声明:以数据成员的方式描述数据部分,以成员函数(方法)的方式描述公有接口
②类方法定义:描述如何实现类成员函数
简单地说,类声明提供蓝图,类方法定义提供细节。
类声明
//类声明
//stock00.h
#include<iostream>
class Stock//class不同于模板参数的typename,不能代替,Stock为新类型名
{
private://私有部分,一般是数据通项
std::string company;
long shares;
double share_val;
double total_val;
void set_tot()
{total_val = shares*share_val;}
public://公有部分,一般是组成类成员函数声明
void acquire(const std::string &co,long n, double pr);
void buy(long num,double price);
void sell(long num,double price);
void update(double price);
void show();
};
使用类对象的程序都可以使用公有部分,但只能通过公有成员函数访问对象的私有成员。将实现细节放在一起并将它们与抽象分开被称为封装。
实现类成员函数
成员函数的定义与常规函数定义非常相似,它们有函数头和函数体,也可以有返回类型和参数,但还有两个特殊的特征:
①定义成员函数,使用作用域解析符::来表示函数所属的类
②类方法可以访问类的private组件
void Stock::update(double price)//update是Stock类的成员函数,还可以将另一个类的成员函数声明为update
//标识符update()具有类作用域
// stock00.cpp -- implementing the Stock class
// version 00
#include <iostream>
#include "stock00.h"
void Stock::acquire(const std::string & co, long n, double pr)
{
company = co;
if (n < 0)
{
std::cout << "Number of shares can't be negative; "
<< company << " shares set to 0.\n";
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
void Stock::buy(long num, double price)
{
if (num < 0)
{
std::cout << "Number of shares purchased can't be negative. "
<< "Transaction is aborted.\n";
}
else
{
shares += num;
share_val = price;
set_tot();
}
}
void Stock::sell(long num, double price)
{
using std::cout;
if (num < 0)
{
cout << "Number of shares sold can't be negative. "
<< "Transaction is aborted.\n";
}
else if (num > shares)
{
cout << "You can't sell more than you have! "
<< "Transaction is aborted.\n";
}
else
{
shares -= num;
share_val = price;
set_tot();
}
}
void Stock::update(double price)
{
share_val = price;
set_tot();
}
void Stock::show()
{
std::cout << "Company: " << company
<< " Shares: " << shares << '\n'
<< " Share Price: $" << share_val
<< " Total Worth: $" << total_val << '\n';
}
方法与对象
创建对象:
Stock kate,joe;
使用成员函数:
kate.show();
joe.show();
创建的每一个对象都有自己的存储空间,用于存储其内部的变量和类成员,但同一个类的所有对象共享同一组类的方法,即每种方法只有一个副本,在OOP中,调用成员函数被称为发送消息,因此将同样的消息发送给两个不同的对象将调用同一个方法,但该方法被用于两个不同的对象
// usestok0.cpp -- the client program
// compile with stock.cpp
#include <iostream>
#include "stock00.h"
int main()
{
Stock fluffy_the_cat;
fluffy_the_cat.acquire("NanoSmart", 20, 12.50);
fluffy_the_cat.show();
fluffy_the_cat.buy(15, 18.125);
fluffy_the_cat.show();
fluffy_the_cat.sell(400, 20.00);
fluffy_the_cat.show();
fluffy_the_cat.buy(300000,40.125);
fluffy_the_cat.show();
fluffy_the_cat.sell(300000,0.125);
fluffy_the_cat.show();
// std::cin.get();
return 0;
}
类的构造函数与析构函数
声明和定义构造函数
Stock (const string &co,long n =0, double pr = 0.0);//没有返回类型,构造函数声明
//定义构造函数
Stock::Stock(const std::string & co, long n, double pr)
{
company = co;
if (n < 0)
{
std::cout << "Number of shares can't be negative; "
<< company << " shares set to 0.\n";
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
使用构造函数
构造函数初始化对象有两种方式:
Stock food = Stock("World Cabbage",250,2.5);//显示调用构造函数
Stock garmer("Furry Mason",50,1.25);//隐式调用构造函数
Stock *pstock = new Stock("Electroshock Games",18,20.5);//对象指针
无法使用对象调用构造函数,因为在构造函数构造出对象之前,对象是不存在的,因此构造函数创建对象但不能通过对象调用
默认构造函数(defult constructor)
默认构造函数实在未提供显示初始值时,用来创建对象的构造函数。如果没有提供任何构造函数,C++将自动提供默认构造函数,它是默认构造函数的隐式版本,不做任何工作。默认构造函数没有参数,因为没有声明中不包含值
定义默认构造函数的方式有两种:
Stock(const string &co="ERROR",int n=0,double pr=0);//给已有构造函数的所有参数提供默认值
Stock();//函数重载,一个没有任何参数的构造函数。
//只有能有一种默认构造函数,不要同时采用
析构函数(destructor)
用构造函数创建一个对象后,程序负责跟踪该对象,直到其过期为止。对象过期时,程序将自动调用一个特殊的成员函数完成清理工作。
和构造函数一样,析构函数的名称很特殊。在类名前加上~,没有返回值和声明类型,并且没有参数:
~Stock();
①如果创建的是静态存储类对象,析构函数将在程序结束时自动调用
②如果创建的是自动存储类对象,析构函数将在程序运行完代码块时自动被调用
③如果对象是通过new创建,析构函数将驻留在栈内存或者自由存储区中,当使用delete释放内存时,析构函数将会自动被调用
④程序创建临时对象来完成特定操作,在这种情况下,程序将结束该对象的使用时自动调用其析构函数。
// stock10.h ?Stock class declaration with constructors, destructor added
#ifndef STOCK1_H_
#define STOCK1_H_
#include <string>
class Stock
{
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_tot() { total_val = shares * share_val; }
public:
Stock(); // default constructor
Stock(const std::string & co, long n = 0, double pr = 0.0);
~Stock(); // noisy destructor
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show();
};
#endif
// stock1.cpp ?Stock class implementation with constructors, destructor added
#include <iostream>
#include "stock10.h"
// constructors (verbose versions)
Stock::Stock() // default constructor
{
std::cout << "Default constructor called\n";
company = "no name";
shares = 0;
share_val = 0.0;
total_val = 0.0;
}
Stock::Stock(const std::string & co, long n, double pr)
{
std::cout << "Constructor using " << co << " called\n";
company = co;
if (n < 0)
{
std::cout << "Number of shares can't be negative; "
<< company << " shares set to 0.\n";
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
// class destructor
Stock::~Stock() // verbose class destructor
{
std::cout << "Bye, " << company << "!\n";
}
// other methods
void Stock::buy(long num, double price)
{
if (num < 0)
{
std::cout << "Number of shares purchased can't be negative. "
<< "Transaction is aborted.\n";
}
else
{
shares += num;
share_val = price;
set_tot();
}
}
void Stock::sell(long num, double price)
{
using std::cout;
if (num < 0)
{
cout << "Number of shares sold can't be negative. "
<< "Transaction is aborted.\n";
}
else if (num > shares)
{
cout << "You can't sell more than you have! "
<< "Transaction is aborted.\n";
}
else
{
shares -= num;
share_val = price;
set_tot();
}
}
void Stock::update(double price)
{
share_val = price;
set_tot();
}
void Stock::show()
{
using std::cout;
using std::ios_base;
// set format to #.###
ios_base::fmtflags orig =
cout.setf(ios_base::fixed, ios_base::floatfield);
std::streamsize prec = cout.precision(3);
cout << "Company: " << company
<< " Shares: " << shares << '\n';
cout << " Share Price: $" << share_val;
// set format to #.##
cout.precision(2);
cout << " Total Worth: $" << total_val << '\n';
// restore original format
cout.setf(orig, ios_base::floatfield);
cout.precision(prec);
}
// usestok1.cpp -- using the Stock class
// compile with stock10.cpp
#include <iostream>
#include "stock10.h"
int main()
{
{
using std::cout;
cout << "Using constructors to create new objects\n";
Stock stock1("NanoSmart", 12, 20.0); // syntax 1
stock1.show();
Stock stock2 = Stock ("Boffo Objects", 2, 2.0); // syntax 2
stock2.show();
cout << "Assigning stock1 to stock2:\n";
stock2 = stock1;//可以将一个对象赋给同类型的另一个对象
cout << "Listing stock1 and stock2:\n";
stock1.show();
stock2.show();
cout << "Using a constructor to reset an object\n";
stock1 = Stock("Nifty Foods", 10, 50.0); // temp object
cout << "Revised stock1:\n";
stock1.show();
cout << "Done\n";
}
// std::cin.get();
return 0;
}
const成员函数
void show()const;//将const放在函数括号后面
C++11列表初始化
Stock hot = {"Dedwadd dfwf fw",110,23.2};
Stock dw {"sdded dad",121,2.1};//与构造函数匹配
Stock temp {};//与默认构造函数匹配
this指针
this指针指向用来调用成员函数的对象。
stock1.topval(stock2)//this设置为stock1的地址
每个成员函数包括构造函数和析构函数都有一个this指针,this指针指向调用对象,在函数括号后面使用const限定符将this限定为const,这样不能使用this修改对象的值。
对象数组
声明对象数组的方法与声明标准类型数组相同
Stock mystuff[4];
可以用构造函数来初始化数组元素,在这个情况下必须为每个元素调用构造函数:
Stock stocks[4] = {
Stock("dqguydi dfwq",12.5,20),//也可以交叉使用默认构造函数
Stock("dswd",12.2,21),
Stock("dedes ded"12.6,78),
Stock("dsve fgte"32.9,89)
};