首页 > 编程语言 >C++学习笔记

C++学习笔记

时间:2024-05-06 10:25:30浏览次数:37  
标签:函数 int age 笔记 学习 Person void C++ public

参考


  • 面向对象编程的3大特点
    • 封装
    • 继承
    • 多态
  • struct 声明的类里的成员都是public
  • class 声明的类的成员都是private的,需要通过类的public的成员函数来访问private的成员变量
  • this是一个指针,指向当前对象
  • 引用命名空间里的类或者函数:
    • 使用命名空间A里的类B,有3种方法:
      • 在引用B的位置都用A::B
      • 在开头加上using A::B;,后面可以直接使用B
      • 在开头加入using namespace A;
  • C++里的打印需要引用头文件iostream,然后用cout来输出,在使用cout时需要导入std命名空间
    • 如: cout<<"Hello World"<<endl;
  • 重载:函数名相同,参数不同(类型、数量、顺序不同)
    • 注意: 这里不包括函数的返回值的类型
  • 引用和指针:引用相当于变量的别名
    	int a = 100;
    	int &b = a;
    	int *c = &a;
    	b的类型是引用,b相当于a的别名,b和a表示同一块内存,跟指针不同。
    	c的类型是指针,c有自己的存储空间,其中存放的是a的地址。
    
  • 构造函数:跟类名相同的成员函数,只看名字,不看参数
    • 有了构造函数,可以实现在定义对象时直接初始化,类似结构体变量在定义时初始化那样,例如:
      class Person {
      private:
      	int age;
      	char *name;
      public:
      	Person() {}
      	/* 如果用户没有传name,那么使用默认值"none" */
      	person(int age, char *name = "none")
      	{
      		this.age = age;
      		this.name = name;
      	}
      };
      
      void main()
      {
      	Person per;  // 注意:不可以写成Person per();
      	Person per2(10);
      
      	Person *per3 = new Person;
      	Person *per4 = new Person();
      	Person *per5 = new Person[2]; //  数组,调用两次构造函数
      	Person *per6 = new Person(10, "Xiaoming");
      
      	delete per3;
      	delete per4;
      	delete [] per5;
      	delete per6;
      }
      
    • 系统会默认提供一个无参数的构造函数
    • 如果自己实现了一个有参数的构造函数,那么也必须自己实现一个无参数的构造函数
  • 析构函数:跟类名相同的成员函数,并且前面有一个~
class Person {
public:
        Person() {
                cout << "Create\n" << endl;
        }

        ~Person() {
                cout << "Delete\n" << endl;
        }
};
	- 系统会默认提供一个无参数的析构函数

int main(int argc, const char *argv[])
{
        int i = 0;

		// 通过new创建的对象存活到调用delete,或者进程结束
        for (i = 0; i < 10; i++) {
                Person *per = new Person();
        }

		// 通过下面的方式创建的对象类似函数的局部变量,在栈里分配
		// 每个for循环调用构造和析构
		for (i = 0; i < 10; i++) {
                Person per;
        }

        return 0;
}
  • 拷贝构造函数

    • 默认拷贝构造函数:值拷贝,如果有指针类型的成员,那么只拷贝指针的值
    	Person per;
    	Person per2(per);
    
    • 自定义拷贝构造函数
    class Person {
    public:
    	Person(Person &per) {
    		this.name = new char[strlen(per.name)+1];
    		strcpy(this.name, per.name)
    	}
    }
    
  • 成员初始化列表

    • 只能用于构造函数
    • 必须用来初始化非静态const成员数据
    • 必须用来初始化引用类型的成员数据
    • 格式:
      	Classy:Classy(int n, int m) : mem1(n), mem2(0), mem3(n*m + 2)
      	{
      	// ...
      	}
      
  • 不同作用域的对象构造函数的调用顺序

    • 全局对象在main函数之前构造
    • 其余的根据程序的执行顺序进行构造
    • 在函数体内部的static对象,只构造一次
  • 内部有其他类的对象的类构造顺序

    • 根据在类内部出现的顺序进行构造,最后调用当前类的构造函数。默认调用的是这些内部对象的无参数的构造函数
    • 如果需要调用内部对象的有参数的构造函数,需要在当前类对应的构造函数上标明
  • 内部有其他类的对象的类析构顺序:跟上面构造的顺序相反

  • 类内部的static类型的成员属于整个类,然后需要使用类名::静态成员来访问

    • 为了不创建对象也可以访问静态变量,需要在类外面定义:
    int Person::cnt = 0;
    int Person::get_count(void) {
    	return cnt;
    }
    class Person {
    private:
    static int cnt ;
    public:
    static get_count(void);
    };
    
    • 在类的静态函数里面不能访问属于对象的成员,因为后者是非静态的,不能确定是那个对象
    • 在类的静态函数里可以直接访问类的静态变量,不用在前面加类名
  • 友元函数:如果函数func在类A里面被声明为friend,那么func可以访问A的private成员

	class Person{
	private:
	int age;

	public:
	friend Person add (Person &per1, Person &per2);
	};

	Person add(Person &per1, Person &per2) {
		Person p;
		p.age = per1.age + per2.age;
		return p;
	};
- 注意:友元函数并不是类的成员函数
  • 操作符重载

    • 加法操作的重载
    	class Person{
    	private:
    	int age;
    
    	public:
    	friend Person operator+ (Person &per1, Person &per2);
    	};
    
    	Person operator+(Person &per1, Person &per2) {
    		Person p;
    		p.age = per1.age + per2.age;
    		return p;
    	};
    
    • 对++i的重载
    	class Person{
    	private:
    	int age;
    
    	public:
    	friend Person operator++ (Person &per1);
    	};
    
    	Person operator++(Person &per1) {
    		per1.age++;
    		return per1;
    	};
    	// 或者
    	Person &operator++(Person &per1) {
    		per1.age++;
    		return per1;
    	};
    
    • 对i++的重载
    	class Person{
    	private:
    	int age;
    
    	public:
    	friend Person operator++ (Person &per1, int a);
    	};
    
    	Person operator++(Person &per1, int a) {
    		Person tmp;
    		tmp = per1;
    		per1.age++;
    		return tmp;
    	};
    
    • 对输出<<的重载
    ostream& operator<<(ostream &o, Person p) {
    	cout<<"age: "<<p.age;
    	return o;
    }
    
  • 继承:class A : public B

    • 从一个类派生出另一个类时,原始类称为基类,继承类称为派生类
    • public、protected和private类型的成员的区别
      • 不能直接拿父亲的私房钱:派生类不能直接访问基类的private成员
      • 可以问父亲要钱:需要通过基类的protected/public成员函数来访问基类的private成员
      • 儿子总是比外人亲:派生类可以直接访问基类的protected成员,但是其他代码不可以,这里说的派生类可以访问是指在派生类的成员函数中可以访问
      • public的成员,外界可以直接访问
      • 在派生类中可以调整从基类继承过来的成员的权限(调高或者调低),前提是派生类可以看到基类的成员,比如基类的private成员,在派生类中就看不到
    • public、protected和private在继承方面的区别
      image
    • 复写
      • 派生类有跟基类相同的成员,名字和参数都一样
    • 多重继承:继承多个基类, class A: public B, public C
      • 如果不写public的话,默认是private继承
      • 如果这些基类中有同名的成员,在派生类中访问会存在二义性,解决方法有2种:
        • 在派生类访问时指明用的是哪个基类的成员:a.B::func();
        • 将同名的成员单独抽象出来,消除同名的成员,单独抽象出来的基类通过虚拟继承来实现:class A: virtual public B {};
      • 尽量避免使用多重继承
    • 构造顺序:
      • 先调用基类的构造:多个基类之间根据继承的顺序构造,从左到右
        • 先调用虚拟基类
        • 后一般基类
      • 自身:
        • 对象成员的构造(类的某些成员是其他类的对象)
        • 自己的构造函数
  • 多态:相同的调用方法调用的是不同的类里的成员函数

    • 虚函数:
      class Person {
      private:
      int age;
      public:
      virtual int get_age(void) {return age;}
      };
      
    • 在使用指针和引用来使用对象时,才会有多态
    • 只有类的成员函数才能声明为虚函数
    • 静态成员函数不能是虚函数
    • 内联函数不能是虚函数
    • 构造函数不能是虚函数
    • 析构函数一般都声明为虚函数
    • 重载的函数不能是虚函数,重载是名字相同,但是参数不同
      • 但是如果返回值是当前类的对象的指针或者引用时可以设置为虚函数
    • 复写:函数参数、返回值相同,可以设为虚函数
    • 静态联编:非虚函数,在编译时确定好调用哪个
    • 动态联编:对象里面有指针指向虚函数表,通过指针找到虚函数表,调用其中的函数
  • 类型转换:xxx_cast<type_id> (expression)

    • reinterpret_cast<>: 相当于C风格的使用小括号的强制类型转换,这种方式无法去掉const属性
    • const_cast<>:用于去掉const属性
    • dynamic_cast<>: 动态类型转换,type_id必须是类的指针、类的引用或者void *
      • 如果type_id是类指针的引用,那么expression也必须是一个指针
      • 如果type_id是一个引用,那么expression也必须是一个引用
      • 用于多态场合,即:必须有虚函数
      • 有可能转换成功,也有可能转换失败,比强制类型转换更加安全
    • static_cast<>: 静态类型转换,编译的时候检查是否可以转换成功
      • 上行转换安全
      • 下行转换不安全
    • 上行转换:把派生类的对象转换为基类的对象
    • 下行转换:把基类的对象转换为派生类的对象
  • 抽象类:含有纯虚函数的类,抽象类不能实例化对象,抽象类用于向派生类定义框架,不提供实现,向上提供统一的接口

    • 纯虚函数:虚函数后面跟“=0”,如下所示:
    class Person{
    public:
    virtual int get_age(void) = 0;  // 不提供实现,只提供框架接口
    };
    
    • 派生类如果没有全部复写完基类的纯虚函数,那么这个派生类也是抽象类
    • 析构函数不应该使用纯虚函数
  • 函数模板

template<typename T>
T& mymax(T& a, T& b)
{
	cout<<__PRETTY_FUNCTION__<<endl;
	return (a < b)? b : a;
}


int main(int argc, char **argv)
{
	int ia = 1, ib = 2;
	float fa = 1, fb = 2;
	double da = 1, db = 2;
	
	mymax(ia, ib);
	mymax(fa, fb);
	mymax(da, db);

	return 0;
}
  • 类模板
template<typename T>
class AAA {
private:
	T t;
public:
	void test_func(const T &t);
	void print(void);
};

template<typename T> void AAA<T>::test_func(const T &t)
{
	this->t = t;
}


template<typename T>
void AAA<T>::print(void)
{
	cout<<t<<endl;
}

int main(int argc, char **argv)
{
	AAA<int> a;

	a.test_func(1);
	a.print();

	AAA<double> b;

	b.test_func(1.23);
	b.print();

	return 0;
}
- 类模板的重写
```c++
template<typename T>
class AAA {
private:
	T t;
public:
	void test_func(const T &t);
	void print(void);
};

template<typename T> void AAA<T>::test_func(const T &t)
{
	this->t = t;
}


template<typename T>
void AAA<T>::print(void)
{
	cout<<t<<endl;
}

template<>
class AAA<int> {
public:
	void test_func_int(const int & t)
	{
		cout<<t<<endl;
	}
	void print_int(void);
};

void AAA<int>::print_int(void)
{
	cout<<"for test"<<endl;
}

int main(int argc, char **argv)
{
	AAA<int> a;

	a.test_func_int(1);
	a.print_int();

	AAA<double> b;

	b.test_func(1.23);
	b.print();

	return 0;
}
```

标签:函数,int,age,笔记,学习,Person,void,C++,public
From: https://www.cnblogs.com/pengdonglin137/p/17962193

相关文章

  • Spring学习之——Bean加载流程
    Spring IOC容器就像是一个生产产品的流水线上的机器,Spring创建出来的Bean就好像是流水线的终点生产出来的一个个精美绝伦的产品。既然是机器,总要先启动,Spring也不例外。因此Bean的加载流程总体上来说可以分为两个阶段:容器启动阶段Bean创建阶段一、容器启动阶段:容器的启动阶......
  • 动手学深度学习——基本张量运算
    基本张量运算张量张量可以被看做多维数组,高维矩阵,可以进行多种数据操作和数学运算importtorchtorch.tensor([[1.,-1.],[1.,-1.]])创建张量tensor([[1.,-1.],[1.,-1.]])a=torch.randn(2,3)torch.sigmoid(a)a处理张量tensor([[-0.1690,-0.2554,-0.4......
  • Linux学习第一天
    参考正点原子Linux开发文档。记录下知识点。Shell基本操作前面我们说Shell就是“敲命令”,那么既然是命令,那肯定是有格式的,Shell命令的格式如下:command-options[argument]command:Shell命令名称。options:选项,同一种命令可能有不同的选项,不同的选项其实现的功能不同。......
  • 五一假期学习总结:从DevOps到SRE
    大家好,我是Edison。五一假期,没出远门,带娃露营玩水玩沙骑平衡车,累的不亦乐乎。同时,也刷了一门极客时间的课程《SRE实战总结》,给我带来了一些新的认知,我将这些认知整理了以下,特此总结分享与你,强烈建议已经实践了DevOps的童鞋了解一下SRE。什么是SRE?SRE全称SiteReliabilityEngi......
  • TinyRender学习笔记
    通过手写软光栅渲染器加深对计算机图形学基本原理的理解,并练习C++面向对象程序设计。github链接:blackbird2003/blackbirdTinyRenderer(github.com)该项目主要参考Home·ssloy/tinyrendererWiki(github.com)编写推荐先过一下GAMES101Lesson0GettingStartedUsingTGAi......
  • 《自动机理论、语言和计算导论》阅读笔记:p402-p427
    《自动机理论、语言和计算导论》学习第13天,p402-P427总结,总计26页。一、技术总结无。二、英语总结1.eludee--,assimilatedformofex-(out,away)+ludere(toplay,seeludicrous)。vt.ifsthyouwanteludesyou,youdonotsucceedinachievingit。p426,Mor......
  • c++综合实验报告友元
    综合性、设计性实验报告专业:计算机科学与技术 一、实验目的:1.熟练掌握友元函数和友元类设计的方法2.掌握友元函数的含义,友元函数和成员函数的区别。3.掌握友元类的含义。二、实验仪器或设备:微型计算机三、总体设计(设计原理、设计方案及流程等)实验内容:定义Student类和Sco......
  • sqlserver笔记
    明确的性能低的定义:在现有资源还没有达到最大吞吐量的前提下,系统如果不能满足合理的预期表现。最小化每个SQL的响应时间;合理增加吞吐量;减少网络延时优化磁盘IO、CPU能够协调、平衡的运行,合理的响应外部的请求,实现资源利用的最大化。影响性能的常见因素:1.数据库结构的设计--了解......
  • 如何用费曼技巧快速学习任何东西
    如何用费曼技巧快速学习任何东西为什么教学是理解的关键理查德·费曼是一位诺贝尔物理学奖得主,在量子力学、粒子物理等领域做出了重大贡献。他还开创了量子计算,引入了纳米技术的概念。他是康奈尔大学和加州理工学院的著名讲师。尽管取得了这些成就,费曼认为自己只是一个"努力......
  • 面试必问并发编程内存模型JMM与内存屏障剖析 学习
    总课程:1、JMM。每个线程会产生一个变量副本。如下图所示,第二个变量修改了变量initFlag,但线程1并不会退出,是因为每个线程产生了副本。----解决方法:volatileCPU缓存一致性协议:MESI机制,以及内存模型底层八大原子操作。Volatile缓存可见性实现原理:底层实现主要通过汇编lock前......