第一个c++工程
1、创建项目,修改名字、路径创建
2、文件创建文件,或右击对应文件新建.cpp文件
第一个程序打印“hello world”
#include <iostream>
//#include 宏-----后面紧跟的内容是库文件或者用户自定义头文件
//<>-------首先到标准库里面寻找
//""-------首先从当前项目开始寻找,然后到标准库里找
//iostream----是c++标准库提供的文件,所以没有加.h,C语言的库文件在c++里使用也不需要.h,只需要在头文件前加c,如:#include <cstdio>,如果是用户自定义头文件才需要
//iostream----cout是ostream的实例化,ostream在iostream里面实例化
using namespace std;//使用标准库提供的命名空间std,cout、clog、cin、endl、ends等都是属于命名空间std
int main()
{
cout << "hello wrold" << endl;
//cout输出流对象,用于输出相关信息
//endl结束换行流对象,类似于 c里的“\n、\r”
//<< ----- 相当于输出仪器
//“hello world”向控制台输出的内容
return 0;//程序结束标志
//c++注释 快捷键 Ctrl+shift+/
}
内存模型与名字空间
1.命名空间的使用
? 有名(有名字)的命名空间
? 声明格式:
? 关键字---------namespace
? namespace 标识符的名称
? {
? //代码块或者是语句块
? }
例如:
namespace zhang
{
int a;
}
访问命名空间的内容
访问格式1:针对单一内容访问(一对一访问)
? 符号:域作用符号--------由两个冒号组成----------::
? 命名空间的名称::需要访问的内容
例如:
namespace zhang
{
int a;
}
访问命名空间的内容
zhang::a;
访问格式2:使用using关键字和作用域符号可以让命名空间的某一个内容在一个局部作用域有效(多对一访问)
? 关键字:using
? 格式:
? using 命名空间名称::需要访问的内容
例如:
namespace zhang
{
int a;
}
访问命名空间的内容2
{
using zhang::a;
//在这个花括号内访问a就是zhang这个命名空间的a
a = 10;
cout << a << endl;
int b = a;
cout << b << endl;
}
访问格式3:使用关键字using和namespace关键字访问,如果在全局使用就说明这个程序都使用这个命名空间的所有内容,如果在局部使用就说明这个局部作用域都使用这个命名空间的所有内容
? 关键字:using、namespace
? 格式: using namespace 空间名称; 例如:
namespace zhang
{
int a;
}
访问命名空间的内容2
//全局使用到a都是zhang这个空间中的这个a
using namespace zhang
{}
局部使用到a都是zhang这个空间中的这个a
{
using namespace zhang
}
例:
#include <iostream>
using namespace std;
namespace zhang
{
int a = 10;
}
using namespace zhang;
int main()
{
cout << zhang::a << endl;
{
using zhang::a;
cout << "a=" << a << endl;
int b = a;
cout << "b=" << b << endl;
int c = a;
cout << "c=" << c << endl;
}
}
2.无名(没有名字)的命名空间
? 声明格式:
? namespace
? {
? //代码
? }
? 可以当全局变量或函数直接使用
注意:命名空间是可以进行嵌套的
例题1
#include <iostream>
using namespace std;
namespace NS
{
int i, j;
int max(int x, int y)
{
return x >= y ? x : y;
}
}
int main()
{
NS::i = 6; NS::j = 7;
{
using namespace NS;
i++;
j++;
cout << "max=" << max(i, j) << endl;
}
return 0;
}
3、作用域 C++与C语言一样,花括号里面的属于局部作用域,花括号外属于全局作用域。 如: 类作用域: 在类{};体内区域,称之为类作用域,如果变量声明或定义在类体内,那么生命期只在该类存在超出类失效 命名空间作用域: ? 命名空间是全局的一部分,它实质也是全局的内容,如果变量声明或定义在命名空间内,那么这个变量的生命周期是在这个命名空间里可见,超出命名空间必须使用域作用符号才能访问,否则就不能使用该变量 4.动态内存
? 动态内存:程序运行时才分配的空间,称之为动态内存,例如,在C语言里,使用malloc和free两个函数,来动态开辟堆区空间和释放堆区空间,c++提供了new和delete操作符来操作堆区空间(动态开辟空间) 操作符:new 格式: 数据类型(内置的基本的数据类型和自定义的数据类型) * 标识符名称 = new 数据类型 ; 例如:
int * p = new int ;//在堆区开辟int类型大小的空间,并且用p指向该空间
或
int * p ;
p =new int ;
释放变量地址空间:
delete p;
int * p = new int (50);//开辟堆空间的时候同时对该空间进行初始化工作,初始化为50
释放:
delete p;
1、类
描述现实世界中的事物,用C++进行报编程时,通常将现实世界中的事物来进行描述。类的关键字:class,类是一个泛指,不是特指某一个事物。即类是群体。
用 类描述事物的格式:
class 类名(标识符名称)
{
? //特征-----变量
? //行为-----函数
}
例如:描述一个人,人具备:姓名、年龄、性别、肤色,行为:吃饭、睡觉、走路
class Person
{
public:
string name;//姓名
int age;//年龄
string sex;//性别
string complexion;//肤色
//吃饭
void eat()
{
cout << "正在吃饭!" << endl;
}
//睡觉
void sleep()
{
cout << "正在睡觉!" << endl;
}
//走路
void walk()
{
cout << "正在走路!" << endl;
}
};
2、对象
? 对象是类的实例化,特指一类的某一个,例如:人(泛指)----------对人实例化-----------为张三(特指)
对象实例化格式:
1.在栈区实例化------------栈区实例化,不需要用户手动释放内存,编译器自动回收
格式:
? 类名 对象名(标识符);
例如:
Person person;
2.在堆区实例化------------堆区实例化,需要用户手动释放内存,如果 不释放,容易造成内存泄漏
格式:
? 类名 对象名(标识符名称) = new 类名;
例如:
Person *people = new Person;
3、访问类的成员(成员变量+函数 )
根据实例化的方式不同,访问方式不同
a.在栈区实例化
? 对象名(标识符名称).成员;
?
person.eat()
b.堆区实例化
对象名(标识符名称)->成员
例如:
people->sleep();
4、类的成员修饰符
? 作用:为了保护类的成员,C++提供了三种类的成员修饰符
public(公共)、protected(受保护的)、private(私有的)
1.public(公共)
? 用户把变量或者是函数放置在类的public下,那么变量或函数就是类的公共属性
public作用范围:
? 从public:后面开始一直到类体结束都是属于public属性下的成员
a.在public下的成员对整个类都是可见的
b.在public下的成员对与类外部是可见的
c.在public下的成员对有元函数也是可见的
d.在public下的成员对于派生类(子类)也是可见的
2.private(私有的)
? 用户把变量或者是函数放置在类的private下,那么变量或函数就是类的私有属性
a.在private下的成员对整个类都是可见的
b.在private下的成员对与类外部是不可见的
c.在private下的成员对有元函数也是可见的
d.在private下的成员对于派生类(子类)也是不可见的
3.protected(受保护的)
用户把变量或者是函数放置在类的protected下,那么变量或函数就是类的受保护属性
a.在protected下的成员对整个类都是可见的
b.在protected下的成员对与类外部是不可见的
c.在protected下的成员对有元函数也是可见的
d.在protected下的成员对于派生类(子类)也是可见的
如果有两个或多个访问修饰符从开始到下一个开始的内容属当前开始修饰符
#include <iostream>
using namespace std;
class Test
{
public:
int a = 50;
void fun1()
{
cout << "a=" << a << endl;
cout << "这是test1" << endl;
}
private:
int b = 50;
void fun2()
{
cout << "b=" << b << endl;
cout << "这是test1" << endl;
}
protected:
int c = 50;
void fun3()
{
cout << "c=" <<c << endl;
cout << "这是test1" << endl;
}
};
int main()
{
Test test;
cout << "test.a=" << test.a << endl;
test.fun1();
cout << "test.b=" << test.b << endl;
test.fun2();
cout << "test.c=" << test.c << endl;
test.fun3();
return 0;
}
注:
? 1.如果类没有写任何提示符,那么该类的成员都在private下
? 2.一般成员变量放在private下
5、构造函数
? 构造函数是一种特殊的函数,它实质还是称为函数如果用户没有显示的书写构造函数,编译器会自动生成一个构造函数,只是不会显示,反之就是自己写
格式:
? 类名(参数列表)
{
? //代码块----用于初始化类的成员变量
}
例如:
People(参数列表)
{
}
如何去初始化类的成员变量:
? (1)直接初始化类的成员变量
例如:
class Test
{
public:
int a;
Test()
{
a=10;
}
}
? (2)初始化参数列表
格式:
? 类名(参数列表):变量名1(值1),变量名2(值2)
class Test
{
public:
int age;
string name;
Test():age(10),name("zhangsna")
{
}
}
? (3)如何调用构造函数
a.构造函数的显示调用
格式;
? 类名 对象名(构造函数参数列表);//这时候就是显示调用类的构造函数
例如:
? People people();
b.构造函数的隐式调用
格式:
? 类名(构造函数参数列表);//这时候就是显示调用类的构造函数
例如:People();
》》总结:构造函数与普通函数的区别
不同点:
- 普通函数前有返回类型,构造函数没有
- 普通没有初始化列表,构造函数后有初始化列表
- 普通函数调用的时候只可以以显示调用方式,构造函数有显示调用和隐式调用
不同点:
- 都可以带参数或不带参数
- 都可以重载
6、析构函数
? C++的析构函数是一种特殊函数,实质也是函数,如果用户没有自己书写析构函数,编译器会自动生成一个隐藏的析构函数
作用:释放空间
格式:
~类名()
{
? //代码块
}
例如:
~Test1()
{
? cout << "这是一个析构函数" << endl;
}
7、拷贝构造函数
? 拷贝-----copy,如果用户需要用一个对象去初始化另一个对象的时候,就会遇到拷贝构造函数,其实质是一个构造函数,如果用户没有自己手动设置,编译器会自动生成
C:
? int a =10;
? int b = a;
C++:
? 用于两个对象(自定义的类型)之间的初始化
? People people1;
? People people2=people1;
拷贝构造函数的格式:
? 类名(const 类名 & obj)
? {
? //拷贝构造
? }
(1)浅拷贝 ? 是将拷贝的对象的地址传给新的对象,也就是说新对象与拷贝对象指向同一块内存 (2)深拷贝 ? 是将拷贝的对象的值传给新的对象,也就是说新对象与拷贝对象指向不同内存块
#include <iostream>
using namespace std;
class Person
{
public:
string* name = new string;
string sex;
int age;
Person()
{
*name = "李四";
age = 20;
sex = "男";
}
Person(const string * Name,int Age,string Sex)
{
*name = *Name;
age = Age;
sex = Sex;
}
Person(const Person& obj)
{
*name = *obj.name;
age = obj.age;
sex = obj.sex;
}
~Person()
{
delete name;
}
void print()
{
cout << "姓名:" << *name << "性别:" << sex << "年龄:" << age << endl;
}
};
int main()
{
Person P1;
string s = "张三";
Person P2(&s, 20, "男");
Person P3(P2);
P1.print();
P2.print();
P3.print();
}
this指针
? this指针存在于类的普通成员函数,c++提供this指针是为了解决二义性问题
原型:
? 成员函数(类名 * const register this)
使用:
? this->类成员
注意:
? 静态成员函数和友元函数中没有this指针
标准输入和输出流
(1)cout:标准输出
console out:控制台输出
从内存里获取数据输出到控制台,之间经过缓冲区
格式:
? cout(是ostream类的对象,并且是在iostream里进行实例化)<<基本数据类型(不需要用户指定,编译器可以自动识别数据类型) 输出多个数据:
? cout << 数据1 << 数据2 << 数据3 << 数据4……;
符号:<<
? 在C语言里,<<是移位运算符,只能用于基本数据类型的数据的移位操作,
? 在C++里,该运算符进行了重载的工作,可以用于其他类型的数据,在输出这里,可以用于输出数据 (2)cerr:标准的错误输出流 ? 从内存里获取错误的数据(程序运行的时候,产生的错误)输出到控制台 (3)clog:标准的日志输出流 使用与cout一样 (4)cin:标准的输入流 ? 从磁盘或者终端设备获取数据输入到内存 cin :console input; 使用方式: ? cin >>基本数据类型的变量;//从磁盘或者终端设备获取数据存入到变量里 在C语言里,>>是移位运算符,只能用于基本数据类型的数据的移位操作,在C++里,该运算符进行了重载的工作,可以用于其他类型的数据,在输出这里,可以用于输入数据 什么时候获取输出缓冲区的值
- 当程序执行完成时(main 结束),会自动刷新输出缓冲区一次
- 当遇到endl(换行对象):endline,会自动刷新缓冲区
- 当输出缓冲区满的时候,自动刷新缓冲区
注:iostream里提供了一个宏:BUFSIZ,查看缓冲区大小---------512个字节
重载
(1)重载 一般是发生在函数中,C++也支持运算符重载 解释: C++里的函数名相同、函数的参数个数、类型、顺序不同,可以发生重载(函数重载) 重载用于相同的函数名具有不同的功能时使用 例如:
void function()
{
}
void function(int a)
{
}
继承
一个类的对象拥有另一个类或其他多个类的成员变量和成员方法
单继承: 一个类的对象共享了另一个类的成员变量和成员方法 多继承: 一个类的对象共享了其他多个类的成员变量和成员方法 单继承的格式: class 新的类名(子类) : 继承的权限 已经存在的类(父类) { //类体 }; 多继承格式: ? class 新的类(子类或者派生类):继承权限1 已存在类1,继承权限2 已存在类2,继承权限3 已存在类3 新的类我们称之为子类(派生类),已经存在的类我们称之为父类(基类) 继承的权限:public、private、protected 例如:
class Father
{
public:
int a = 50;
void function()
{
cout << "这是父类的成员函数" << endl;
}
};
class Son : public Father
{
public:
void son_func()
{
cout << "a=" << a << endl;
}
};
int main()
{
Son zhangsan;
zhangsan.son_func();
zhangsan.function();
return 0;
}
继承的权限 ? c++提供的继承权限,目的是对继承进行限制 除了父类的私有属性不可以被访问,其他权限修饰的成员变量或函数都能够被子类访问到,public、protected权限下的成员变量或函数都继承到子类的public权限下,不过能够直接访问的只有父类的public下的变量或函数,父类的private与protected权限下的变量或函数只能通过友元类或友元函数才能访问
#include <iostream>
using namespace std;
class Fathor
{
public:
int a=10;
void fun1()
{
cout << "fun1" << endl;
}
private:
int b=20;
void fun2()
{
cout << "fun2" << endl;
}
protected:
int c=30;
void fun3()
{
cout << "fun3" << endl;
}
friend class Son;
};
class Son:private Fathor
{
public:
Son()
{
Fathor f;
f.fun1();
f.fun2();
f.fun3();
cout << f.a <<" " << f.b <<" " << f.c << endl;
}
protected:
private:
};
int main()
{
Son s;
}
多继承 ? 一个新的类继承多个已经存在的类,多继承。 声明格式: ? class 新的类(子类或者派生类):继承权限1 已存在类1,继承权限2 已存在类2,继承权限3 已存在类3
多态
? c++里“一种接口,多种方法”叫多态,接口是父类的接口,多种方法表示父类中有方法并且子类有相同的方法,不过实现的功能不同,多态用于父类调用方法时执行的是子类的方法(即父类调用子类)
构成多态条件:
- 两个类具有继承关系
- 子类必须重写父类方法(子类方法的内容可以与父类不同)
- 父类中的方法必须是虚函数
#include <iostream>
using namespace std;
class Father
{
public:
int a = 10;
void fun1()
{
cout << "fun1" << endl;
}
virtual void fun()
{
cout << "这是父类的fun" << endl;
}
private:
int b = 20;
void fun2()
{
cout << "fun2" << endl;
}
protected:
int c = 30;
void fun3()
{
cout << "fun3" << endl;
}
friend class Son;
};
class Son :public Father
{
public:
Son()
{
Father f;
f.fun1();
f.fun2();
f.fun3();
cout << f.a << " " << f.b << " " << f.c << endl;
}
void fun()
{
cout << "这是子类的fun" << endl;
}
protected:
private:
};
int main()
{
Father* f1 = new Son;
f1->fun();
Father f2;
f2.fun();
}
抽象类与纯虚函数
在虚函数的声明后面加上“=0”,就表示该虚函数为纯虚函数,它是构成抽象类不可缺少的条件
声明格式: virtual 返回值类型 函数名(参数列表)=0; 例如: virtual void funciton() = 0 ; 注意的点 a、抽象类只是给子类提供一个基类 b、抽象类不能实例化为对象 c、抽象类里只是描述了一些行为,但没有具体实现行为(纯虚函数),需要在子类中去重新实现抽象类的行为 例:
#include<iostream>
using namespace std;
class Student
{
public:
virtual void run() = 0;
};
class MiddleStudent :public Student
{
public:
virtual void run()
{
cout << "两条腿跑" << endl;
}
};
int main()
{
MiddleStudent midstu;
midstu.run();
return 0;
}
虚析构函数:当需要先释放子类的对象在释放父类对象时使用
#include <iostream>
using namespace std;
class Father
{
public:
virtual ~Father()
{
cout << "这是父类的析构函数" << endl;
}
private:
};
class Son :public Father
{
public:
~Son()
{
cout << "这是子类的析构函数" << endl;
}
};
int main()
{
Father* father = new Son;
delete father;
}
异常
在java中也有异常机制,java中使用try……catch捕获异常进行处理,在Java中异常抛出分为手动和自动抛出两种, 手动抛异常使用关键字throw 自动则直接使用try……catch 在c++中,异常不能自动抛出,只有自己手动抛异常,也就是说,throw与try……catch是一起使用的,如果单独使用try……catch不会捕捉到异常存在。 例
#include <iostream>
#include <cmath>
using namespace std;
class Line
{
public:
int a, b, c;
Line(int A, int B, int C)
{
a = A;
b = B;
c = C;
}
void display()
{
cout << "a=" << a << ",b=" << b << ",c=" << c << endl;
}
friend void setpoint(const Line& obj, const Line& line);
};
void setpoint(const Line& obj,const Line& line)
{
double x, y;
if (line.b == 0 || obj.b == 0 )
{
throw 0;
}
else
{
double k1 = (double) - line.a / line.b;
double k2 = (double)- obj.a / obj.b;
if (k1 == k2)
{
throw exception();
}
else
{
x = (line.b * obj.c - obj.b * line.c) / (line.a * obj.b - obj.a * line.b);
y = -(obj.a * x + obj.c) / obj.b;
if (fabs(x) > pow(10, 8) || fabs(x) > pow(10,8))
{
throw out_of_range("x,y不能大于10^8");
}
else
{
cout << "两直线交点是(" << x << "," << y << ")" << endl;
}
}
}
}
int main()
{
Line line1(1,2,100);
Line line2(2,2,112);
line1.display();
line2.display();
try
{
setpoint(line1, line2);
}
catch (int)
{
cout << "直线不是方程" << endl;
}
catch (out_of_range& e)
{
cout << e.what() << endl;
}
catch (exception& e)
{
cout << "两条直线是平行线" << endl;
}
return 0;
}
|