C++ Primer Plus学习笔记

《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是不同的,可以因为这一区别而完成函数重载


 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值