《C++ primer》第五版 第8-14章笔记
1. 宏替代
#include <iostream>
using namespace std;
#define SQUARE(X) ( (X) * (X) )
int main()
{
int c = 3;
// SQUARE(c++)将会被替代为( (c++) * (c++) )
cout << SQUARE(c++) << endl; //将输出9而不是12,将整个表达式计算完之后才递增
cout << c << endl; // 输出5
cin.get();
return 0;
}
2. 临时对象为const类型
double cube( double & x )
{
return x * x * x;
}
int main()
{
double c = 3;
cout << cube( c + 1.0 ) << endl; // 编译错误,c+1.0将产生一个临时对象,而临时
// 对象在c++中都是const类型的,所以将cube的参数类型改为 const double & x即可
return 0;
}
注:1> 实参的类型正确,但不是左值;2> 实参的类型不正确,但可以转换为正确的类型;
这两种情况下,编译器会生成临时对象。P231(c++ perimer第五版)
3. extern定义的变量
//test.cpp
#include <iostream>
using namespace std;
extern int num = 10; // 定义一个变量,外部链接,可以在其他文件中使用num
void show()
{
<span style="white-space:pre"> </span>cout << num << endl;
<span style="white-space:pre"> </span>cout << "hello world" << endl;
<span style="white-space:pre"> </span>return;
}
// test1.cpp
#include <iostream>
using namespace std;
extern int num;
extern void show();
int main()
{
<span style="white-space:pre"> </span>show();
<span style="white-space:pre"> </span>cout << num << endl;
<span style="white-space:pre"> </span>return 0;
}
4. const之前有无extern关键字的区别
例子1:
// 1.cpp num链接性为内部,即只能在1.cpp中使用,这就是为什么可以在头文件中定义const常量,
//然后在其他文件包含该头文件而可以使用const常量
const int num = 0;
void show()
{
cout << num << endl;
return;
}
// 若要使得num为外部变量,即在其他文件中也可以使用,则只需添加extern关键字即可,如下:
extern const int num = 20; // 其他文件中也可以使用num常量,外部链接,此处可以初始化(const数据必须初始化)
// 具体见P278 《c++ primer第五版》
例子2:
// test.cpp
#include <iostream>
using namespace std;
int num = 10; // 定义一个变量,外部链接,可以在其他文件中使用num
void show()
{
cout << "hello world" << endl;
return;
}
// test1.cpp
#include <iostream>
using namespace std;
// extern int num = 15; 错误,有extern并且初始化,相当于定义一个链接性为外部的变量,//即在其他文件中也可以使用此处定义的num常量,但是test.cpp中已经定义了num变量,//所以该处会出现重复定义的编译错误
extern int num; // 正确的声明,表面num在其他文件中已经定义了
extern void show(); // 不需要extern也可以 具体见P278 《c++ primer第五版》
int main()
{
show();
cout << num << endl; // 输出10
return 0;
}
5. 创建的类对象是否能调用构造函数
// 5. h
#include <iostream>
class Stock
{
private:
int m_num;
public:
void set();
Stock();
};
// 6.cpp
#include "5.h"
using namespace std;
void Stock::set() // 前面添加inline则表示内联函数
{
m_num = 2;
std::cout << m_num << std::endl;
return;
}
Stock::Stock()
{
cout << "constructro called" << endl;
}
// main.cpp
#include <cstdlib>
#include <iostream>
#include "5.h"
using namespace std;
int main(int argc, char *argv[])
{
Stock test;
test.set();
test.Stock(); // 编译错误-》构造函数被用来创建对象,而不能通过对象来调用,见P310(C++ Primer第五版)
system("PAUSE");
return EXIT_SUCCESS;
}
6. P315 《C++ Primer第五版》
/
// Filename:Stock.h
/
#ifndef STOCK_H
#define STOCK_H
class Stock
{
private:
char company[30];
int shares;
double share_val;
double total_val;
void set_tot()
{
total_val = shares * share_val;
return;
}
public:
Stock();
Stock( const char *co, int n, double pr = 0.0 );
Stock( const char *pch );
~Stock();
void show();
};
#endif
/
// Filename:Stock.cpp
#include <iostream>
#include "Stock.h"
Stock::Stock()
{
std::cout << "Default constructor called!\n";
std::strcpy( company, "no name" );
shares = 0;
share_val = 0.0;
total_val = 0.0;
}
Stock::Stock( const char *co, int n, double pr )
{
std::cout << "Constructor using " << co << " called\n";
std::strncpy( company, co, 29 );
company[29] = '\0';
if( n < 0 )
{
std::cerr << "Number of shares can not be negative; "
<< company << " shares set to 0.\n";
shares = 0;
}
else
{
shares = n;
}
share_val = pr;
set_tot();
}
Stock::Stock( const char *pch )
{
std::cout << pch << std::endl;
strcpy( company, pch );
}
Stock::~Stock()
{
std::cout << "Bye, " << company << "!\n";
}
void Stock::show()
{
using std::cout;
using std::endl;
cout << "Company: " << company << " Shares: " << shares << endl
<< " Share Price: $" << share_val << " Total Worth: $" << total_val << endl;
return;
}
/
// Filename:main.cpp
#include <iostream>
#include "Stock.h"
int main()
{
using namespace std;
{
Stock stock1( "stock1", 12, 20.0 );
cout << "\nstock1 show:" << endl;
stock1.show();
cout << endl;
Stock stock2 = Stock( "stock2", 2, 2.0 ); // Dev-C++编译运行不会产生临时对象
cout << "stock2 show:" << endl;
stock2.show();
stock2 = stock1;
cout << "\nstock1 show:" << endl;
stock1.show();
cout << "\nstock2 show:" << endl;
stock2.show();
cout << endl;
stock1 = Stock( "temp stock", 10, 50.0 );// Dev-C++编译运行会产生临时对象,并将临时对象赋值给stock1
stock1.show();
cout << "Done\n";
Stock stock3 = "hello stock3"; // Dev-C++编译运行不会调用Stock( const char *pch )产生临时对象,然后赋值 为stock3,然后释放该临时对象,而是直接调用Stock( const char *pch )构造stock3对象
}
cin.get();
return 0;
}
运行结果:
7. 临时对象,拷贝构造函数,析构函数的调用
#include <iostream>
class A
{
private:
int num;
public:
A( int n ):num(n)
{
std::cout << "constructor called " << num << std::endl;
};
A( const A &a ) // 拷贝构造函数
{
std::cout << "A( const A &a )'s &a " << &a << std::endl;
std::cout << "copy constructor called " << std::endl;
std::cout << "A( const A &a )'s this:" << this << std::endl;
this->num = a.num; // 类成员函数可以访问私有变量
}
~A()
{
std::cout << "~A()'s this:" << this << std::endl;
std::cout << "destructor called " << num << std::endl;
}
void print()
{
std::cout << num << std::endl;
}
};
A getA( A a )
{
std::cout << "getA()'s &a:" << &a << std::endl;
return a;
}
int main()
{
using namespace std;
{
A x(20); // 构造函数输出
cout << "main:&x: " << &x << endl;
getA(x).print();
}
cin.get();
return 0;
}
/*
getA(x).print(); 执行流程:
1. 调用类A的拷贝构造函数,传实参x传给拷贝构造函数,用来构造getA函数中的对象a ;
2. getA函数返回时也会调用拷贝构造函数,传实参a给拷贝构造函数,用来在函数外部构造一个临时对象;
3. 临时对象调用成员函数print();
4. 临时对象调用析构函数并释放空间;
5. getA函数中的局部对象a调用析构函数并释放空间;
6. main函数中的对象x调用析构函数并释放空间.
*/
/*
输出结果:
*/
8. 转换函数 P367《C++ Primer第五版》,赋值函数
#include <iostream>
class A
{
private:
int n;
public:
A( int nn):n(nn)
{
std::cout << "constructor called: " << n << std::endl;
}
~A()
{
std::cout << "destructor called: " << n << std::endl;
}
A& operator=( const A &t ) // 赋值函数
{
std::cout << "assign function called" << std::endl;
A::n = t.n;// 用A::n也行
// this->n = t.n;
}
operator int()// 转换函数,将A对象转换为int类型
{
return n;
}
};
int main()
{
using namespace std;
{
A a = 2; // 会调用 A( int nn),不会先构造临时对象,而是直接调用A( int nn)构造对象a
a = 3; // 会先调用 A( int nn)构造临时对象,然后将临时对象赋值给a,完成后,临时对象释放
cout << a << endl; // 将调用转换函数,从而将A类型转换为int类型
cout << (int)a << endl; // 也会调用转换函数
}
cin.get();
return 0;
}
/*
输出结果:
constructor called: 2
constructor called: 3
assign function called
destructor called: 3
3
3
destructor called: 3
*/
9. 返回值对象,拷贝构造函数,编译器优化
#include <iostream>
class A
{
private:
int num;
public:
A( int n ):num(n)
{
std::cout << "constructor called: " << n << std::endl;
}
~A()
{
std::cout << "destructor called: " << num << std::endl;
}
A( const A &a )
{
std::cout << "copy constructor called\n";
this->num = a.num;
}
A& operator=( const A &a ) // 赋值操作符函数
{
std::cout << "= function called\n";
this->num = a.num;
}
friend std::ostream& operator<<( std::ostream &os, const A &a )
{
return os << a.num;
}
};
A getA( int num )
{
A a(num);
std::cout << &a << std::endl;
return a;
}
int main()
{
using namespace std;
{
A a1 = getA(1); // 不会调用拷贝构造函数,getA函数中直接在外部创建对象a1
// 而不会在getA函数中先创建对象a,然后调用拷贝构造函数构造a1,这里
//编译器优化了,直接在外部创建对象a1了,并初始化为1,故getA函数结束时
// 不会释放a了,因为此次调用没有在函数getA中创建局部变量a,而是直接在外部
// 创建对象a1了
cout << &a1 << endl;
cout << a1 << endl;
A a2(4);
a2 = getA(2); // 这里是赋值,故在getA()中创建对象a,然后
// 调用赋值函数,赋值给a2,然后释放函数getA中的对象a
cout << a2 << endl;
}
cin.get();
return 0;
}
/*
输出结果:
constructor called: 1
0x22ff20
0x22ff20
1
constructor called: 4
constructor called: 2
0x22ff00
= function called
destructor called: 2 // 释放getA(2)调用中的对象a
2
destructor called: 2 // 释放对象a2
destructor called: 1 // 释放对象a1
*/
10. P484《C++ primer中文第五版》
#include <iostream>
#include <string>
#include <valarray>
using namespace std;
class Student
{
private:
typedef valarray<double> ArrayDb;
ArrayDb scores;
string name;
public:
Student( int n ):name("Nully"), scores(n) // scores初始化为n个元素
{
}
double& operator[]( int i ) // 函数1 去掉&也能编译通过
{
cout << "operator[](int i) called\n";
return scores[i];
}
double operator[]( int i ) const //该函数与函数1是不同的函数,为函数重载
{
cout << "operator[](int i) const called\n";
return scores[i];
}
friend istream& operator>>( istream &is, Student &stu )
{
cout << "operator>> function called\n";
is >> stu.name;
return is;
}
};
int get()
{
int result = 9;
return result;
}
int main()
{
// cin >> get(); 编译不通过 ..................1
Student stu(1);
cin >> stu; // 调用operator>>
cin >> stu[0]; // 调用double& operator[]( int i ),而不是double operator[]( int i )
// 若只有 double operator[]( int i ) 则会编译有错,类似上面的cin>>get()
cout << stu[0] << endl; // dev-C++中调用double& operator[]( int i )
system("pause");
return 0;
}
//注:函数后面加const与不加const是不同的,可以因为这一区别而完成函数重载