1 封装
封装的好处:数据隐藏;接口简化,隐藏复杂的内部;易于维护和扩展;提高代码重用性。
#include <iostream>
#include <string>
class Person {
private:
std::string name;
int age;
public:
Person(const std::string& name, int age) : name(name), age(age) {} // 构造函数
std::string getName() const {
return name;
}
void setName(const std::string& newName) {
name = newName;
}
int getAge() const {
return age;
}
void setAge(int newAge) {
if (newAge > 0) {
age = newAge;
}
}
};
int main() {
Person person("Alice", 30);
std::cout << "Name: " << person.getName() << ", Age: " << person.getAge() << std::endl;
person.setName("Bob");
person.setAge(25);
std::cout << "Updated Name: " << person.getName() << ", Updated Age: " << person.getAge() << std::endl;
system("pause");
return 0;
}
2 继承
子类拥有父类的属性、方法
class BaseStudent
{
public: // 默认是private的,所以需要指定一下
void print() {
cout << "BaseStudent print!" << endl;
}
};
class DeriveStudent : public BaseStudent
{
public:
};
// 调用:
BaseStudent baseStudent;
DeriveStudent deriveStudent;
baseStudent.print();
deriveStudent.print();
BaseStudent *pBaseStudent = new DeriveStudent();
pBaseStudent->print();
// 输出结果:
BaseStudent print!
BaseStudent print!
BaseStudent print!
请按任意键继续. . .
3 多态
可以用基类的指针指向子类的对象,调用子类的方法
必要条件:有继承关系;虚函数;子类重写该虚函数
class BaseStudent
{
public:
virtual void print() {
cout << "BaseStudent print!" << endl;
}
};
class DeriveStudent : public BaseStudent
{
public:
void print() {
cout << "DeriveStudent print!" << endl;
}
};
// 调用:同上
// 输出结果:
BaseStudent print!
DeriveStudent print!
DeriveStudent print!
请按任意键继续. . .
此外,析构函数最好是虚函数,保证析构时子类能够先析构:
#include<iostream>
using namespace std;
class BaseStudent
{
public: // 默认是private
virtual void print() {
cout << "BaseStudent print!" << endl;
}
virtual ~BaseStudent() { // 为了多态时子类也能够析构,基类的析构需要是虚函数
cout << "BaseStudent deconstructor" << endl;
};
};
class DeriveStudent : public BaseStudent
{
public:
void print() { // 子类重写基类的方法,基类如果是虚函数则构成多态
cout << "DeriveStudent print!" << endl;
}
~DeriveStudent() {
cout << "DeriveStudent deconstructor" << endl;
}
};
int main()
{
BaseStudent* pBaseStudent = new DeriveStudent();
pBaseStudent->print();
delete pBaseStudent;
system("pause");
return 0;
}
// 执行结果:
DeriveStudent print!
DeriveStudent deconstructor
BaseStudent deconstructor
请按任意键继续. . .
4 dynamic_cast用法
在C++中,dynamic_cast 用于在运行时检查对象的类型,并进行安全的向下转型。为了使 dynamic_cast 能够正确工作,基类必须至少有一个虚函数,通常是虚析构函数。这是因为 dynamic_cast 依赖于运行时类型信息(RTTI),而虚函数是实现RTTI的关键。
class Base {
public:
virtual ~Base() {} // 虚析构函数,启用多态
};
class Derived1 : public Base {
public:
void func1() { cout << "Derived1 function" << endl; }
};
class Derived2 : public Base {
public:
void func2() { cout << "Derived2 function" << endl; }
};
int main()
{
Base* b = new Derived1();
Derived1* d1 = dynamic_cast<Derived1*>(b);
if (d1) {
d1->func1();
}
else {
cout << "Failed to cast" << endl;
}
delete b;
d1->func1();
system("pause");
return 0;
}
// 打印结果:
Derived1 function
Derived1 function
请按任意键继续. . .
上面的最后一句.d1->func1();这是为什么呢?d1是野指针吗?
d1 在 delete b; 之后是一个悬挂指针(dangling pointer),指向的内存已经不再有效。在这种情况下,d1 并不是一个野指针(wild pointer),因为野指针是一个未初始化的指针,而 d1 是一个已经被赋值但指向了无效内存的指针。不过,使用这样的指针同样是不安全的。
5 C++ 11构造/析构default用法
#include <iostream>
#include <string>
class MyClass {
public:
MyClass() = default; // 默认构造函数
MyClass(const MyClass&) = default; // 默认拷贝构造函数
MyClass(MyClass&&) = default; // 默认移动构造函数
MyClass& operator=(const MyClass&) = default; // 默认拷贝赋值运算符
MyClass& operator=(MyClass&&) = default; // 默认移动赋值运算符
~MyClass() = default; // 默认析构函数
};
int main() {
MyClass obj1; // 使用默认构造函数
MyClass obj2 = obj1; // 使用默认拷贝构造函数
MyClass obj3 = std::move(obj1); // 使用默认移动构造函数
obj1 = obj2; // 使用默认拷贝赋值运算符
obj1 = std::move(obj3); // 使用默认移动赋值运算符
system("pause");
return 0;
}
在C++中,std::move 是一个标准库函数,它将一个对象转换为右值引用,这是为了触发移动构造函数或移动赋值运算符,而不是拷贝构造函数或拷贝赋值运算符。使用 std::move 可以显著提高性能,因为它避免了不必要的资源拷贝。
6 移动构造函数
#include <iostream>
#include <vector>
class MyClass {
public:
std::vector<int> data;
MyClass(MyClass&& other) : data(std::move(other.data)) {
std::cout << "Move constructor called" << std::endl;
}
MyClass() {
std::cout << "Constructor called" << std::endl;
}
~MyClass() {
std::cout << "Destructor called" << std::endl;
}
};
MyClass createObject() {
MyClass obj;
obj.data.push_back(1);
obj.data.push_back(2);
obj.data.push_back(3);
return obj; // 这里调用移动构造函数
}
int main() {
MyClass myObject = createObject();
return 0;
}
// 运行结果:
Constructor called
Move constructor called
Destructor called
请按任意键继续. . .
7 移动赋值运算符
#include <iostream>
#include <vector>
class MyClass {
public:
std::vector<int> data;
MyClass() { // 默认构造函数
std::cout << "Default constructor called" << std::endl;
}
MyClass(MyClass&& other) : data(std::move(other.data)) { // 移动构造函数
std::cout << "Move constructor called" << std::endl;
}
MyClass& operator=(MyClass&& other) { // 移动赋值运算符
std::cout << "Move assignment operator called" << std::endl;
if (this != &other) { // 避免自赋值
data = std::move(other.data);
}
return *this;
}
~MyClass() {
std::cout << "Destructor called" << std::endl;
}
};
int main() {
MyClass obj1; // 调用默认构造函数
obj1.data.push_back(1);
obj1.data.push_back(2);
obj1.data.push_back(3);
MyClass obj2; // 调用默认构造函数
obj2 = std::move(obj1); // 调用移动赋值运算符
// 验证 obj1 是否被清空
if (obj1.data.empty()) {
std::cout << "obj1 has been moved from, and is now empty." << std::endl;
}
system("pause");
return 0;
}
// 运算结果:
Default constructor called
Default constructor called
Move assignment operator called
obj1 has been moved from, and is now empty.
请按任意键继续. . .