class Sales_data{
public:
Sales_data() = default;// 默认合成 默认构造函数
Sales_data(const Sales_data& ) = default;// 默认合成 拷贝构造函数
Sales_data& operator=(const Sales_data&);// 拷贝赋值运算符
~Sales_data() = default;// 默认合成 默认析构函数
};
Sales_data& Sales_data::operator=(const Sales_data&) = default;// 拷贝赋值运算符 类外定义
struct NoCopy(){// struct 默认为 public
NoCopy() = default;// 默认合成 默认构造函数 不能是删除函数
NoCopy(const NoCopy&) = delete;// 阻止拷贝
NoCopy& operator=(const NoCopy&);// 阻止赋值
~NoCopy() = default;// 默认合成 默认析构函数 不能是删除函数
};
class privateCopy{// class 默认为 private 普通用户无法访问
privateCopy(const privateCopy&);// 私有拷贝构造函数
privateCopy& operator=(const privateCopy&);// 私有拷贝赋值运算符
public:
privateCopy() = default; // 默认合成 默认构造函数
~privateCopy() = default;// 默认合成 默认析构函数 不能是删除函数
};
struct Node{
char* name;//名字 字符指针
int age;// 年龄
Node(char* n = " ", int a = 0 ){//默认构造函数
name = strdup(n);// strdup()字符串拷贝库函数
age = a;
}
// 拷贝构造函数未定义 编译器自动生成一个(自动生成的 只是逐个对成员复制,遇到指针就会出问题)
// 拷贝赋值运算符也未定义 编译器自动生成一个(自动生成的 只是逐个对成员复制,遇到指针就会出问题)
};
// 执行拷贝时 指针对象会指向同一个对象
Node node1("Role", 20), node2(node1);//使用node1 初始化 node2
strcpy(node2.name, "Wendy");// 指向了同一个对象
node2.age = 30;// 非指针正常赋值
cout << node1.name << " " << node1.age << " " << node2.name << " " << node2.age << endl;
// Wendy 20 Wendy 30 //
struct Node{
char* name;//名字 字符指针
int age;// 年龄
Node(char* n = " ", int a = 0 ){//默认构造函数
name = strdup(n);// strdup()字符串拷贝库函数
age = a;
}
// 拷贝构造函数
Node(const Node& n){
name = strdup(n.name);
age = n.age;
}
// 拷贝赋值运算符也未定义 编译器自动生成一个 (自动生成的 只是逐个对成员复制,遇到指针就会出问题)
};
Node node1("Role", 20), node2(node1);//使用node1 初始化 node2 使用拷贝构造函数
strcpy(node2.name, "Wendy");
node2.age = 30;// 正常赋值
cout << node1.name << " " << node1.age << " " << node2.name << " " << node2.age << endl;
// Role 20 Wendy 30 //
struct Node{
char* name;//名字 字符指针
int age;// 年龄
Node(char* n = " ", int a = 0 ){//默认构造函数
name = strdup(n);// strdup()字符串拷贝库函数
age = a;
}
// 拷贝构造函数
Node(const Node& n){
name = strdup(n.name);
age = n.age;
}
// 拷贝赋值运算符
Node& operate=(const Node& n){
if(this != &n){// 确保赋值运算符的两边不是同一个类的同一个对象,避免重复 定义自己
if(name != 0) free(name);//先释放之前的内存(如果之前已经指向了内存,避免内存泄漏)
name = strdup(n.name);// 再用 等号 左边的对象初始化 对象
age = n.age;
}
return *this;// this 起始就是 类对象的地址
}
};
struct Node{ char* name;//名字 字符指针 int age;// 年龄 Node(char* n = " ", int a = 0 ){//默认构造函数 name = strdup(n);// strdup()字符串拷贝库函数 age = a; }
// 拷贝构造函数
Node(const Node& n){
name = strdup(n.name);
age = n.age;
}
// 拷贝赋值运算符
Node& operate=(const Node& n){
if(this != &n){// 确保赋值运算符的两边不是同一个类的同一个对象,避免重复 定义自己
if(name != 0) free(name);//先释放之前的内存(如果之前已经指向了内存,避免内存泄漏)
name = strdup(n.name);// 再用 等号 左边的对象初始化 对象
age = n.age;
}
return *this;// this 起始就是 类对象的地址
}
// 定义析构函数 ~Node(){ if(name != 0) free(name);//指针不为空,就已经使用了指向的内存,需要free手动释放掉 } };
class refTest{
public:
int& getRefN(){
return n;//n为类内私有变量 返回该私有变量引用后 类外就可以访问它
}
int getN(){
return n;//n为类内私有变量
}
private:
int n;
} c;
//c.n = 6;// 错误 外部直接访问不了 类内私有变量
int& k = c.getRefN();//通过返回引用 可以间接访问修改 类内私有变量
k = 7;// 类内私有变量 n 被修改为 7
cout << c.getN();// 可以看到 n 被修改为 7
c.getRefN() = 10;//直接通过 c.getRefN() 来给 类内私有变量 n 赋值
// 一般定义成 非成员函数 在{};外面
ostream& operator<<(ostream& os, const Sales_data& item ){
os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
// 使用了 字符串的、int、double的 输出运算符 类构成类的 输出运算符
return os;
}
istream& operator>>(istream& is, const Sales_data& item ){
double price;// 单价
is >> item.bookNo >> item.units_sold >> price;
if(is)//检测输入是否成功
item.revenue = item.units_sold * price
else
item = Sales_data();//输入失败,对象呗赋予默认的状态
return is;
}
// 关系运算符 返回类型为 bool 输入两个类对象的 常量 引用 避免拷贝 节省时间 常量限制 避免修改 bool operator==(const Sales_item &lhs, const Sales_item &rhs) { // 在类中被是定义为 friend 有元函数 // friend bool operator==(const Sales_item&, const Sales_item&);// 重定向 等于符号 == return lhs.units_sold == rhs.units_sold && lhs.revenue == rhs.revenue && lhs.isbn() == rhs.isbn(); }
#ifndef SALESITEM_H
// we're here only if SALESITEM_H has not yet been defined
#define SALESITEM_H
// Definition of Sales_item class and related functions goes here
#include <iostream>
#include <string>
class Sales_item {
// these declarations are explained section 7.2.1, p. 270
// and in chapter 14, pages 557, 558, 561
// 操作符 定义
friend std::istream& operator>>(std::istream&, Sales_item&);// 重定向输入 >> 符号
friend std::ostream& operator<<(std::ostream&, const Sales_item&);// 重定向输出 << 符号
friend bool operator<(const Sales_item&, const Sales_item&);// 重定向 小于符号 <
friend bool operator==(const Sales_item&, const Sales_item&);// 重定向 等于符号 ==
public:
// constructors are explained in section 7.1.4, pages 262 - 265
// default constructor needed to initialize members of built-in type
Sales_item() = default;
Sales_item(const std::string &book): bookNo(book) { }
Sales_item(std::istream &is) { is >> *this; }
public:
// operations on Sales_item objects
// member binary operator: left-hand operand bound to implicit this pointer
Sales_item& operator+=(const Sales_item&);
// operations on Sales_item objects
std::string isbn() const { return bookNo; }
double avg_price() const;
// private members as before
private:
std::string bookNo; // implicitly initialized to the empty string
unsigned units_sold = 0; // explicitly initialized
double revenue = 0.0;
};
// used in chapter 10
inline
bool compareIsbn(const Sales_item &lhs, const Sales_item &rhs)
{ return lhs.isbn() == rhs.isbn(); }
// nonmember binary operator: must declare a parameter for each operand
Sales_item operator+(const Sales_item&, const Sales_item&);
inline bool
operator==(const Sales_item &lhs, const Sales_item &rhs)
{
// must be made a friend of Sales_item
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool
operator!=(const Sales_item &lhs, const Sales_item &rhs)
{
return !(lhs == rhs); // != defined in terms of operator==
}
// assumes that both objects refer to the same ISBN
Sales_item& Sales_item::operator+=(const Sales_item& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_item
operator+(const Sales_item& lhs, const Sales_item& rhs)
{
Sales_item ret(lhs); // copy (|lhs|) into a local object that we'll return
ret += rhs; // add in the contents of (|rhs|)
return ret; // return (|ret|) by value
}
std::istream&
operator>>(std::istream& in, Sales_item& s)
{
double price;
in >> s.bookNo >> s.units_sold >> price;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * price;
else
s = Sales_item(); // input failed: reset object to default state
return in;
}
std::ostream&
operator<<(std::ostream& out, const Sales_item& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_item::avg_price() const
{
if (units_sold)
return revenue/units_sold;
else
return 0;
}
#endif
template<class genType>//声明模板类型
class genClass{
genType storage[50];//模板类型 数组
};
// 定义
genClass<int> intObject; // int 类型数组
genClass<double> doubleObject;// double 类型数组
// 其二也可以将 数组大小推迟定义
template<class genType, int size = 50>// 声明模板类型 书序大小默认为50
class genClass{
genType storage[size];//模板类型 数组
};
// 定义
genClass<int> intObject1; // int 类型数组 默认 大小
genClass<int, 100> intObject2; // int 类型数组 数组大小为 100
genClass<double, 123> doubleObject; // double 类型数组 数组大小为 123
// 交换两个变量的值
template<class genType>//声明模板类型
void my_swap(genType& num1, genType& num2){ // 注意为 引用 需要对实参修改
genType temp = num1;
num1 = num2;
num2 = temp;
}
#include <iostream>
using namespace std;
// 基类
class BaseClass {
public://共有类型 哪里都可以访问
BaseClass() { }//默认构造函数
void f(char *s = "unknown") {
cout << "Function f() in BaseClass called from " << s << endl;
h();//类内可以访问 类的私有函数
}
protected:// 保护类型 子类 和 友元函数/有元类 可以访问
void g(char *s = "unknown") {
cout << "Function g() in BaseClass called from " << s << endl;
}
private:// 类内 和 元函数/有元类 可以访问
void h() {
cout << "Function h() in BaseClass\n";
}
};
// 子类 Derived1Level1 共有继承自 基类 BaseClass
class Derived1Level1 : public virtual BaseClass {
public:
void f(char *s = "unknown") {
cout << "Function f() in Derived1Level1 called from " << s << endl;
g("Derived1Level1");// 本子类没有重写g() 因此调用的是 父类的g() 保护类型可以继承 子类内可以访问
// 函数时调用的基类的 但是参数 还是按子类传入的
h("Derived1Level1");// 本子类重写了h()(本身父类的为私有,子类也调用不了), 因此调用的是 自己的 h()
}
void h(char *s = "unknown") {
cout << "Function h() in Derived1Level1 called from " << s << endl;
}
};
class Derived2Level1 : public virtual BaseClass {
public:
void f(char *s = "unknown") {
cout << "Function f() in Derived2Level1 called from " << s << endl;
g("Derived2Level1");// 调用基类的g() 保护类型的函数 但是参数按 子类传入的参数
// h(); // 错误 : h()为基类的 私有函数 ,子类访问不了 BaseClass::h() is not accessible
}
};
//二级继承
class DerivedLevel2 : public Derived1Level1, public Derived2Level1 {
public:
void f(char *s = "unknown") {
cout << "Function f() in DerivedLevel2 called from " << s << endl;
g("DerivedLevel2");// g()函数只有基类有 实现 调用的是基类的 保护继承g() 但是参数是 子类 最新传递的
Derived1Level1::h("DerivedLevel2");// 父亲Derived1Level1有h() 爷爷 也有h() 需要指定调用的哪一个 参数都是最新的
BaseClass::f("DerivedLevel2");// f()函数 两个父亲 和 一个爷爷都有实现,需要指明调用哪一个 参数都是最新的
}
};
int main() {
BaseClass bc;//基类
Derived1Level1 d1l1;//子类1
Derived2Level1 d2l1;//子类2
DerivedLevel2 dl2;//子类的子类
bc.f("main(1)");//
// bc.g(); // 错误: 保护类型 类外访问不了 BaseClass::g() is not accessible
// bc.h(); // 错误: 私有类型 类外访问不了 BaseClass::h() is not accessible
cout << "---------------"<< endl;
d1l1.f("main(2)");//首先调用子类重写的 f()
// 内部调用了 基类的g()(函数时调用的基类的 但是参数 还是按子类传入的 ) 和 自身重写的 h()
// d1l1.g(); // 错误: 在子类内 可以访问父类的保护类型函数g(), 外面访问不了 BaseClass::g() is not accessible
d1l1.h("main(3)");// 调用子类自己重写的函数 参数按最新传入的
d2l1.f("main(4)");// 调用子类的函数f(),内部调用了父类的b保护类型函数g() 但是参数按子类传入的参数
// d2l1.g(); // 父类的保护函数g() 在子类内可以访问 ,外部访问不了 错误 BaseClass::g() is not accessible
// d2l1.h(); // 父类的私有函数 子类内,外部都访问不了 错误: BaseClass::h() is not accessible
dl2.f("main(5)");//类自身f() 内部 爷爷的 g() 父亲1的 h() 爷爷的 f() 参数都是最新传入的
// dl2.g(); // error: BaseClass::g() is not accessible
dl2.h();//外部能访问 父亲 Derived1Level1的 共有类型函数 h()
return 0;
}
/*
Function f() in BaseClass called from main(1)
Function h() in BaseClass
Function f() in Derived1Level1 called from main(2)
Function g() in BaseClass called from Derived1Level1
Function h() in Derived1Level1 called from Derived1Level1
Function h() in Derived1Level1 called from main(3)
Function f() in Derived2Level1 called from main(4)
Function g() in BaseClass called from Derived2Level1
Function f() in DerivedLevel2 called from main(5)
Function g() in BaseClass called from DerivedLevel2
Function h() in Derived1Level1 called from DerivedLevel2
Function f() in BaseClass called from DerivedLevel2
Function h() in BaseClass
Function h() in Derived1Level1 called from unknown
--------------------------------
Process exited with return value 0
Press any key to continue . . .
*/
多态性指的是获得多种形态的能力。
在 OOP 中,多态性指的是用同样的函数名称表示多个函数,而这些函数是不同对象的成员。
对于所谓的静态绑定来说,调用哪个函数是在编译阶段确定的。
而对于动态绑定,则要推迟到运行阶段才能确定。
在 C++中,动态绑定是通过将成员函数声明为 virtual 来实现的。在这种方式中,
如果对虚函数成员进行调用,那么选择执行哪个函数
并不依赖于声明的指针类型,而是依赖于指针当前指向的类型。
#include <iostream>
using namespace std;
//类1
class Class1 {
public:
virtual void f() {//虚函数 支持动态绑定 运行时确定
cout << "Function f() in Class1\n";
}
void g() {// 静态绑定 在编译阶段确定
cout << "Function g() in Class1\n";
}
};
// 类2
class Class2 {
public:
virtual void f() {//虚函数 支持动态绑定 运行时确定
cout << "Function f() in Class2\n";
}
void g() {
cout << "Function g() in Class2\n";
}
};
//类3
class Class3 {
public:
virtual void h() {//虚函数 支持动态绑定 运行时确定
cout << "Function h() in Class3\n";
}
};
int main() {
Class1 object1, *p;// 类1 对象 object1 指针 p 声明为 Class1*类型
Class2 object2;// 类2 对象 object2
Class3 object3;// 类3 对象 object3
p = &object1;//当前p 指向 Class1类的 object1对象
p->f();// 动态绑定 到 Class1类的 f()虚函数 Function f() in Class1
p->g();// 静态绑定 在编译阶段确定 Function g() in Class1
p = (Class1*) &object2;// 当前p 指向 Class2类的 object2对象
p->f();// 动态绑定 到 Class2类的 f()虚函数 Function f() in Class2
p->g();// 静态绑定 在编译阶段确定 Function g() in Class1
p = (Class1*) &object3;// 当前p 指向 Class3类的 object3对象
p->f(); // 程序会结束 报错 Class3类 无虚函数 f() devc测试 竟然输出了 Function h() in Class3
p->g(); // 静态绑定 在编译阶段确定 Function g() in Class1
//p->h(); // h() is not a member of Class1;
return 0;
}
/*
该程序的输出如下所示:
Function f() in Class1
Function g() in Class1
Function f() in Class2
Function g() in Class1
// 程序会结束 Class3类 无虚函数 f() devc测试 竟然输出了 Function h() in Class3
Function g() in Class1
*/
多态性是 OOP 的一项强大功能。可以利用这个特性将一个标准消息发送给许多不同的对象,
而不需要指定如何处理消息,也不需要知道对象是什么类型。接收者负责解释和处理消息。发送者
不需要根据接收者的类型来修改消息,也不需要使用 switch 或 if-else 语句。此外还可以在复杂的程
序中加入新的单元而不需要重新编译整个程序。
class C {
int n;//class 默认 属性为 provide 私有
friend class B;//有元类
friend int f();//有元函数
} obc;
int f(){
return 10 * obc.n; // 函数f() 可以访问 类C的对象 obc 的所有类型的变量和方法
}
class B {// 函数B 可以访问 类C的对象 obc 的所有类型的变量和方法
int m;
int function(){
return obc.n;
}
}
class classfuc{
public:
classfuc() {// 默认构造函数
}
double operator() (double x){// 重载函数运算符 ()
return 2*x;
}
double dou(double x){//定义功能函数
return 2*x
}
};
//定义使用 重载了函数运算符的类 定义的函数
double sum2(classfuc f, int n, int m){
double res = 0.0;
for (int i = n; i < = m; ++i){
res += f(i);
// res += f.dou(i);//使用 功能函数
}
return res;
}
// 使用函数
classfuc fc;
cout << sum2(cf, 2, 10) << endl;