void modifyByValue(int n) {
n += 10; // 修改n的值,但不影响实参
}
void modifyByReference(int &n) {
n += 10; // 修改n的值,实参也会受到影响
}
int main() {
int a = 5;
modifyByValue(a); // a的值不变
modifyByReference(a); // a的值变为15
return 0;
}
return_type function_name(parameter1 = default_value1, parameter2 = default_value2, ...) {
// 函数体
}
#include
using namespace std;
// 带默认参数值的函数
void printInfo(int a, int b = 10, int c = 20) {
cout << "a = " << a << ", b = " << b << ", c = " << c << endl;
}
int main() {
printInfo(5); // a = 5, b = 10, c = 20
printInfo(5, 15); // a = 5, b = 15, c = 20
printInfo(5, 15, 25); // a = 5, b = 15, c = 25
return 0;
}
带默认形参值的函数是C++中提高代码复用性和灵活性的一种方式,使得函数接口更加友好和方便。
return_type function_name(parameter_type1, parameter_type2, ...) {
// 函数体
}
return_type function_name(other_parameter_type1, other_parameter_type2, ...) {
// 另一个函数体
}
public
、private
等。const
成员函数。#include
using namespace std;
// 函数重载示例
void print(int a) {
cout << "Integer: " << a << endl;
}
void print(double a) {
cout << "Double: " << a << endl;
}
void print(const char* a) {
cout << "String: " << a << endl;
}
int main() {
print(5); // 调用 int 版本的 print
print(3.14); // 调用 double 版本的 print
print("Hello"); // 调用 const char* 版本的 print
return 0;
}
函数重载是C++中实现多态性的一种形式,它允许程序员定义具有相同名称但操作不同类型数据的函数,增加了代码的可读性和灵活性。
class 类名 {
public:
// 公有成员,可以被外部访问
数据类型 成员变量;
void 方法();
private:
// 私有成员,只能在类内部访问
数据类型 私有变量;
};
class Clock {
public:
// 公有数据成员
int hour;
int minute;
int second;
// 公有成员函数
void setTime(int h, int m, int s) {
hour = h;
minute = m;
second = s;
}
// 私有数据成员
private:
int timeZone;
// 私有成员函数(通常用于数据验证等内部逻辑)
bool isValidTime(int h, int m, int s) {
return (h >= 0 && h < 24 && m >= 0 && m < 60 && s >= 0 && s < 60);
}
};
类的定义是面向对象编程的核心概念之一,它允许程序员创建具有特定属性和行为的对象。通过合理地使用访问权限,可以保证数据的安全性和类的易用性。
new
(对于动态分配)或直接声明来创建对象。class 类名 {
// 类定义
};
int main() {
类名 对象名; // 在栈上创建对象
类名 *指针名 = new 类名; // 动态分配对象
return 0;
}
.
)运算符访问对象的成员变量和成员函数。Clock myClock; // 创建Clock类的对象
myClock.hour = 12; // 访问并设置数据成员
myClock.showTime(); // 调用成员函数
Clock clocks[5]; // 创建包含5个Clock对象的数组
for (int i = 0; i < 5; ++i) {
clocks[i].setHour(i * 2); // 设置每个对象的小时
}
Clock *clockPtr = &myClock; // 指向对象的指针
clockPtr->hour = 3; // 通过指针访问成员
new
操作符在堆上为对象分配内存。delete
操作符释放动态分配的对象。对象是面向对象编程中的核心概念,它将数据和行为封装在一起,提供了一种直观的方式来模拟现实世界中的实体。通过创建和使用对象,可以实现程序的模块化和数据的封装。
void
。class 类名 {
public:
// 构造函数声明
类名(参数列表) {
// 初始化代码
}
};
int main() {
类名 对象名(实参列表); // 创建对象并调用构造函数
return 0;
}
class 类名 {
public:
// 复制构造函数声明
类名(const 类名& 引用);
};
类名::类名(const 类名& 其他) {
// 使用其他对象的状态来初始化当前对象
}
class Clock {
public:
Clock(int h, int m, int s) : hour(h), minute(m), second(s) {}
// 复制构造函数
Clock(const Clock& other) : hour(other.hour), minute(other.minute), second(other.second) {}
// 成员变量
int hour, minute, second;
};
int main() {
Clock clock1(12, 0, 0); // 使用普通构造函数创建对象
Clock clock2 = clock1; // 使用复制构造函数创建对象
return 0;
}
构造函数和复制构造函数是类设计中的重要组成部分,它们确保了对象在创建和复制时具有正确的初始状态。正确地实现和使用这些构造函数对于保证程序的正确性和健壮性至关重要。
~
符号。delete
操作符时。class 类名 {
public:
// 析构函数声明
~类名() {
// 清理代码
}
};
int main() {
类名 对象名; // 对象生命周期结束时,调用析构函数
return 0;
}
class Resource {
public:
Resource() {
// 假设分配了一些资源
}
~Resource() {
// 释放资源
}
};
int main() {
Resource r; // Resource的构造函数被调用
return 0; // Resource的析构函数被调用
}
析构函数是面向对象编程中管理资源的重要工具,它确保了即使在发生异常时,对象占用的资源也能被正确释放。正确实现析构函数对于防止内存泄漏和其他资源管理问题至关重要。
class Engine {
public:
void start() {
// 启动引擎的代码
}
};
class Car {
public:
Car() : engine() {} // 在构造Car时,初始化引擎成员
void startEngine() {
engine.start(); // 使用聚合的Engine对象的行为
}
private:
Engine engine; // Car聚合了Engine对象
};
类聚合是面向对象设计中的一种常见模式,它允许灵活地组合不同的功能,同时保持各个类的独立性和可重用性。通过聚合,可以在不同的上下文中重用已有的对象,同时保持代码的清晰和组织性。
class 类名 {
public:
类名(参数列表) : 初始化列表 {
// 构造函数体
}
};
class Person {
public:
Person(const std::string& name, int age)
: name_(name), age_(age) { // 使用初始化列表直接初始化成员变量
}
private:
std::string name_;
int age_;
};
class Point {
public:
Point(double x, double y) : x_(x), y_(y) {} // 初始化列表
private:
double x_;
double y_;
};
构造函数的初始化列表是C++中一种高效且必要的初始化方式,特别是对于需要直接初始化的成员变量。它不仅提高了代码的可读性,还有助于保持成员变量的有效状态。
class 前向引用的类名;
// 假设有两个类,存在循环依赖
class A; // 前向声明类A
class B {
public:
A* memberA; // B类中包含对A的指针
};
class A { // 定义类A
public:
void functionB(B b); // A类中的函数接受B类的对象作为参数
};
前向引用声明是C++中管理复杂类依赖关系的重要工具,它有助于简化头文件的包含关系,避免编译错误,并提高代码的模块化。
int globalVar = 10; // 全局作用域
void function() {
int localVar = 5; // 局部作用域
{
int localVar = 7; // 嵌套的局部作用域,隐藏了外层的localVar
// ...
}
// 使用localVar会报错,因为这里的localVar指的是外层的localVar
}
::
来明确指定变量的作用域。namespace MyNamespace {
int localVar = 20;
}
int main() {
int localVar = 10; // 局部变量,与MyNamespace::localVar不同
MyNamespace::localVar; // 明确指定命名空间的作用域
}
作用域和可见性是C++中重要的概念,它们帮助程序员控制变量和对象的生命周期,以及在不同部分的程序中如何访问它们。正确地理解和使用作用域和可见性规则对于编写清晰、可维护的代码至关重要。
static
关键字。static
关键字。int globalVar; // 全局变量,静态生存期
void function() {
static int staticVar; // 局部静态变量,静态生存期
int localVar; // 局部变量,动态生存期
// ...
}
static
关键字声明的变量也会保持它们的值,直到程序结束。new
操作符在堆上为对象分配内存,这会延长对象的生存期,直到使用delete
操作符释放内存。int* dynamicArray = new int[10]; // 动态分配数组
delete[] dynamicArray; // 释放分配的数组
理解静态生存期和动态生存期的概念对于管理程序中资源的生命周期至关重要。正确地处理变量和对象的生存期可以避免内存泄漏和其他资源管理错误。
类名::静态成员名
的方式访问。class Counter {
public:
static int count; // 静态成员变量声明
Counter() { // 构造函数
count++; // 每次创建对象时,计数增加
}
};
int Counter::count = 0; // 静态成员变量定义和初始化
int main() {
Counter obj1;
Counter obj2;
std::cout << "Total objects created: " << Counter::count << std::endl;
return 0;
}
class MathUtils {
public:
static int factorial(int n) { // 静态成员函数
if (n <= 1) return 1;
return n * factorial(n - 1);
}
};
int main() {
std::cout << "Factorial of 5: " << MathUtils::factorial(5) << std::endl;
return 0;
}
静态成员是面向对象编程中实现数据和行为共享的重要机制。它们为类提供了一种存储和管理所有对象共享数据的方式,同时保持了数据的封装性和一致性。
friend
关键字声明友元函数。class MyClass {
private:
int privateData;
public:
void publicMethod() {
// ...
}
// 声明友元函数
friend int getPrivateData(MyClass& obj);
};
// 定义友元函数
int getPrivateData(MyClass& obj) {
return obj.privateData; // 直接访问私有成员
}
class FriendClass; // 前向声明
class MyClass {
public:
void publicMethod() {
// ...
}
// 声明友元类
friend class FriendClass;
};
友元函数是一种强大的机制,可以在不破坏封装性的前提下,允许外部函数访问类的私有数据。然而,由于它们对封装原则的影响,应当在确保必要性和合理性的情况下使用。
const
成员函数)是被声明为const
的成员函数,意味着这些函数保证不会修改类的任何成员变量。const
成员函数中,所有成员变量都是const
,因此不能修改它们。const
关键字。class MyClass {
public:
int getData() const { // 声明常成员函数
return data;
}
// ...
private:
int data;
};
void function(const MyClass& myObj) {
int value = myObj.getData(); // 常对象调用常成员函数
}
const
成员函数内,不能给任何非静态成员变量赋新值。const
成员函数。const
。class Circle {
public:
double getRadius() const { // 常成员函数,返回半径
return radius;
}
void setRadius(double r) { // 非const成员函数,设置半径
radius = r;
}
private:
double radius;
};
int main() {
const Circle c(1.0); // 创建常对象
std::cout << c.getRadius(); // 正确:调用常成员函数
// c.setRadius(2.0); // 错误:不能调用非const成员函数
return 0;
}
常成员函数是C++中实现对象不可变性的重要机制,它们确保了在函数执行过程中对象的状态不会被改变。这在多线程环境中尤其重要,因为const
成员函数可以被安全地在不同的线程中调用,而不必担心数据竞争问题。
const
数据成员)是类中被声明为const
的成员变量,意味着这些变量的值一旦初始化后就不能被修改。class MyClass {
public:
MyClass(int val) : constDataMember(val) { // 使用初始化列表初始化常数据成员
}
private:
const int constDataMember; // 常数据成员
};
int main() {
MyClass myObj(10); // 创建对象时初始化constDataMember
// myObj.constDataMember = 20; // 错误:不能修改常数据成员
return 0;
}
const
关键字初始化,如果类型允许,也可以在类定义内部直接赋值。class MyClass {
public:
static const int staticConstDataMember; // 静态常数据成员声明
};
const int MyClass::staticConstDataMember = 10; // 定义和初始化
int main() {
// MyClass::staticConstDataMember = 20; // 错误:不能修改静态常数据成员
std::cout << MyClass::staticConstDataMember << std::endl;
return 0;
}
常数据成员是C++中实现数据不可变性的一种方式,它们在确保数据安全和一致性方面非常有用。然而,它们需要在构造函数的初始化列表中正确初始化,这是使用常数据成员时需要特别注意的一点。
const
引用)是一种特殊的引用,它绑定到一个对象或变量上,并且不能通过这个引用来修改原对象或变量的值。const
关键字声明引用类型,指明它是一个常引用。void display(const int& num) {
// num 是一个常整型引用,不能通过num修改传入的参数值
std::cout << num << std::endl;
}
int main() {
int value = 10;
display(value); // 正确:传递value的引用给display函数
// display(value + 10); // 错误:常引用必须绑定到一个左值
return 0;
}
const
指针),常引用则不能修改。常引用是C++中一种有用的机制,它提供了一种安全的方式来传递对象,同时保护这些对象不被函数内部修改。这在编写需要接收对象但不需要修改对象的函数时尤其有用。
*
指针符号声明对象指针。nullptr
。class MyClass {
// 类定义
};
int main() {
MyClass obj; // 创建对象
MyClass *ptr = &obj; // 创建对象指针并初始化为对象的地址
return 0;
}
->
运算符来访问对象的成员。&
取得地址的,也可以通过解引用操作符*
来访问。MyClass *ptr = new MyClass(); // 分配动态对象并初始化
ptr->memberFunction(); // 通过指针调用成员函数
(*ptr).memberFunction(); // 通过解引用调用成员函数
delete ptr; // 释放动态分配的对象
nullptr
。new
操作符动态分配对象时,必须使用delete
操作符释放内存,避免内存泄漏。nullptr
,避免空指针解引用。this
是一个隐含的指针,指向调用成员函数的对象。class MyClass {
public:
void showAddress() {
std::cout << "Object address: " << this << std::endl;
}
};
int main() {
MyClass obj;
obj.showAddress(); // 显示对象的内存地址
return 0;
}
对象指针是C++中处理动态对象和实现面向对象编程的重要概念。它们允许程序员通过指针操作对象,实现诸如动态内存分配、对象的多态行为等功能。正确地管理对象指针对于防止内存泄漏和其他资源管理错误至关重要。
this
指针this
指针的概念this
指针是C++中类的非静态成员函数内部的一个隐含指针,指向调用成员函数的对象本身。this
指针的作用this
指针指向调用该成员函数的对象。this
指针用于区分成员变量和局部变量,以及调用类的其他成员函数。this
指针的使用场景this
指针来区分。class MyClass {
int value;
public:
MyClass(int val) : value(val) {}
void printValue() {
std::cout << "Value: " << this->value << std::endl;
// 或者使用 (*this).value,但 this->value 更为常见
}
};
this
指针只在类的非静态成员函数中有效。this
指针是一个指向常对象的指针。this
指针本身是一个指针常量,不能被修改指向其他对象。this
指针的用途this
指针来明确指出正在访问的是成员变量或成员函数。this
指针由编译器自动解析。class MyClass {
int data;
public:
void setData(int d) {
data = d; // 直接赋值
this->data = d; // 使用this指针
}
MyClass* getThis() {
return this; // 返回对象本身的地址
}
};
int main() {
MyClass obj;
obj.setData(10);
MyClass* ptr = obj.getThis(); // 获取对象的地址
return 0;
}
this
指针是C++中类成员函数的一个重要特性,它提供了一种方式来访问和操作当前对象的状态。正确使用this
指针有助于编写清晰和易于维护的代码。
类名::*
语法声明指向数据成员的指针。类名(::*)(参数列表)
语法声明指向成员函数的指针。class MyClass {
public:
int data;
void function() {
std::cout << "Function called" << std::endl;
}
};
int main() {
MyClass obj;
MyClass::* ptrToData = &MyClass::data; // 指向数据成员的指针
(void)obj.*ptrToData = 10; // 使用指针访问并赋值成员变量
void (MyClass::*ptrToFunction)() = &MyClass::function; // 指向成员函数的指针
(obj.*ptrToFunction)(); // 使用指针调用成员函数
return 0;
}
对象名.*指针名
访问数据成员,或(对象名.*指针名)(参数列表)
调用成员函数。class MyClass {
public:
static int staticData;
static void staticFunction() {
std::cout << "Static function called" << std::endl;
}
};
int MyClass::staticData = 0; // 定义和初始化静态成员
int main() {
int* ptrToStaticData = &MyClass::staticData; // 指向静态数据成员的指针
*ptrToStaticData = 5; // 使用指针访问并赋值静态成员变量
void (*ptrToStaticFunction)() = &MyClass::staticFunction; // 指向静态成员函数的指针
(*ptrToStaticFunction)(); // 使用指针调用静态成员函数
return 0;
}
指向成员的指针是C++中一种高级特性,它允许程序员在运行时通过指针操作访问类的成员。这在实现某些设计模式或需要高度灵活性的场合非常有用。然而,由于其复杂性,应当谨慎使用,以避免代码难以理解和维护。
new
进行内存分配new 类型名
或 new 类型名(初始化参数)
int* ptr = new int; // 分配一个整型对象的内存,并初始化为0
int* arrPtr = new int[10]; // 分配一个整型数组的内存
MyClass* objPtr = new MyClass(10); // 分配MyClass对象的内存并初始化
delete
进行内存释放delete 指针名
或 delete[] 数组指针名
new
分配的内存,并调用对象的析构函数。new
分配的内存。delete
对于单个对象,delete[]
对于数组。delete ptr; // 释放单个对象的内存
delete[] arrPtr; // 释放数组的内存
nullptr
,指针仍然指向已释放的内存,成为悬挂指针。delete
释放内存后,不应再次删除同一指针,这可能导致未定义行为。动态内存分配是C++中处理复杂内存管理任务的重要工具,它为程序员提供了更大的控制权,但也需要谨慎使用,以确保内存的正确管理和释放。
public
):基类的公有和保护成员在派生类中保持原有的访问权限。private
):基类的公有和保护成员在派生类中成为私有成员。protected
):基类的公有和保护成员在派生类中成为保护成员。class Base {
public:
Base() {
// 基类的构造代码
}
virtual void show() {
std::cout << "Base show" << std::endl;
}
};
class Derived : public Base {
public:
Derived() : Base() {
// 派生类的构造代码,调用基类的构造函数
}
void show() override {
// 重写基类的show方法
std::cout << "Derived show" << std::endl;
}
};
int main() {
Derived d;
d.show(); // 调用派生类的show方法
return 0;
}
继承是面向对象编程的核心概念之一,它允许程序员创建层次结构的类,并在现有类的基础上构建新的功能。正确使用继承可以提高代码的复用性、可维护性和扩展性。
class Base {
public:
int publicVar;
protected:
int protectedVar;
private:
int privateVar;
};
class PublicDerived : public Base {
// 继承方式示例
};
class PrivateDerived : private Base {
// 继承方式示例
};
class ProtectedDerived : protected Base {
// 继承方式示例
};
继承方式是面向对象编程中重要的概念,它影响着类之间的关系和成员的可见性。合理地使用继承方式有助于构建清晰、灵活的类层次结构。
class Base {
public:
virtual void show() { std::cout << "Base show" << std::endl; }
};
class Derived : public Base {
public:
void show() override { std::cout << "Derived show" << std::endl; }
};
int main() {
Base* basePtr = new Derived(); // 向上转型,类型兼容
basePtr->show(); // 动态绑定,调用Derived::show
// 向下转型需要类型转换,并且可能不安全
// Derived* derivedPtr = (Derived*)basePtr; // 需要检查是否为安全转换
delete basePtr;
return 0;
}
类型兼容规则是多态性的基础,它允许程序在运行时根据对象的实际类型调用相应的函数,提高了程序的灵活性和可扩展性。正确理解和应用类型兼容规则对于设计和实现多态性至关重要。
class Base {
public:
Base(int x) : value(x) {}
int value;
};
class Derived : public Base {
public:
Derived(int x, int y) : Base(x), y_(y) {}
int y_;
};
class Derived {
public:
~Derived() {
// 清理派生类资源
}
};
class Base {
public:
Base() {
std::cout << "Base constructor" << std::endl;
}
~Base() {
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base {
public:
Derived() : Base() {
std::cout << "Derived constructor" << std::endl;
}
~Derived() {
std::cout << "Derived destructor" << std::endl;
}
};
int main() {
Derived d;
// 输出顺序:Base constructor, Derived constructor
// 析构顺序:Derived destructor, Base destructor
return 0;
}
派生类的构造函数和析构函数是面向对象编程中管理对象生命周期的重要部分。它们确保对象在创建和销毁时,所有必要的初始化和清理工作都能得到妥善处理。正确地实现这些函数对于防止资源泄漏和确保程序稳定性至关重要。
::
作用域操作符可以访问被隐藏的基类成员。class Base {
public:
int value;
};
class Derived : public Base {
public:
int value; // 隐藏了基类中的value成员
};
int main() {
Derived d;
d.value = 10; // 访问Derived类中的value成员
std::cout << d.Base::value << std::endl; // 使用作用域操作符访问Base类中的value成员
return 0;
}
理解派生类中作用域的规则对于正确地访问和管理类成员至关重要。这些规则确保了类的封装性和继承的合理性,同时允许程序员在派生类中适当地扩展和重用基类的功能。
::
来明确指定要访问的成员属于哪个基类。class Base {
public:
int value;
};
class Derived1 : public Base {
public:
void show() {
std::cout << value << std::endl; // 二义性问题
}
};
class Derived2 : public Base {
public:
void display() {
std::cout << ::Base::value << std::endl; // 使用作用域操作符解决二义性
}
};
int main() {
Derived1 d1;
d1.show(); // 错误:二义性
Derived2 d2;
d2.display(); // 正确:使用作用域操作符
return 0;
}
virtual
关键字来声明虚基类。class Base {
public:
Base(int x) : value(x) {}
int value;
};
class Derived : virtual Base {
public:
Derived(int x) : Base(x) {} // 显式调用虚基类的构造函数
};
int main() {
Derived d(10);
std::cout << d.value << std::endl; // 正确:没有二义性
return 0;
}
二义性问题是面向对象编程中常见的问题之一,特别是在使用多继承时。掌握如何解决二义性问题对于编写清晰、可维护的代码至关重要。通过使用作用域操作符和虚基类,可以有效地解决这些问题。
virtual
关键字来声明虚基类。class Derived : public virtual Base {
// ...
};
class Base {
public:
Base(int x) : value(x) {}
virtual ~Base() {} // 虚析构函数
int value;
};
class Intermediate : public virtual Base {
// ...
};
class Derived : public Intermediate {
public:
Derived(int x) : Base(x), Intermediate() {
// Base的构造函数首先被调用
}
~Derived() {
// 析构顺序与构造顺序相反
}
};
int main() {
Derived d(10);
return 0;
}
虚基类是C++中处理多继承问题的一种有效机制。通过使用虚基类,可以减少派生类中的冗余基类成员,同时解决由于多路径继承引起的二义性问题。正确地使用虚基类对于设计清晰、高效的类继承结构至关重要。
重载(Overloading):
重写(Overriding):
虚函数(Virtual Functions):
virtual
关键字声明的函数,可以在派生类中被重写。class Shape {
public:
virtual void draw() { std::cout << "Drawing a shape" << std::endl; }
virtual ~Shape() {} // 虚析构函数
};
class Circle : public Shape {
public:
void draw() override { std::cout << "Drawing a circle" << std::endl; }
};
class Square : public Shape {
public:
void draw() override { std::cout << "Drawing a square" << std::endl; }
};
int main() {
Shape* shapes[] = {new Circle(), new Square()};
for (Shape* s : shapes) {
s->draw(); // 多态性:调用实际对象类型的draw方法
}
for (Shape* s : shapes) {
delete s;
}
return 0;
}
多态性是面向对象编程的核心概念之一,它提高了程序的灵活性和可扩展性。通过多态性,可以编写通用的代码来处理不同类型的对象,而具体的实现则由对象的实际类型决定。
class Complex {
public:
double real, imag;
// 成员函数重载
Complex operator+(const Complex& rhs) const {
return Complex(real + rhs.real, imag + rhs.imag);
}
// 友元函数重载
friend Complex operator-(const Complex& lhs, const Complex& rhs);
};
Complex operator-(const Complex& lhs, const Complex& rhs) {
return Complex(lhs.real - rhs.real, lhs.imag - rhs.imag);
}
.
(成员访问)、::
(作用域解析)、? :
(三元运算符)等。[]
、赋值=
、比较==
和!=
等运算符。Complex c1(1.0, 2.0), c2(3.0, 4.0);
Complex c3 = c1 + c2; // 调用成员函数重载
Complex c4 = c1 - c2; // 调用友元函数重载
运算符重载是C++中一种强大的特性,它允许程序员扩展语言的运算符,以适应自定义类型的需求。正确使用运算符重载可以提高代码的表达力和易用性,但也需要谨慎处理,以避免混淆和潜在的错误。
virtual
关键字声明函数,使其成为虚函数。class Base {
public:
virtual void show() { std::cout << "Base show" << std::endl; }
virtual ~Base() {} // 虚析构函数
};
class Derived : public Base {
public:
void show() override { std::cout << "Derived show" << std::endl; }
};
int main() {
Base* basePtr = new Derived();
basePtr->show(); // 动态联编:调用Derived::show
delete basePtr;
return 0;
}
动态联编和虚函数是实现运行时多态的关键机制,它们使得程序能够根据对象的实际类型来调用相应的函数,从而提高了代码的灵活性和可维护性。正确使用虚函数对于设计可扩展的面向对象系统至关重要。
= 0
(在C++98及之前的版本)或= delete
(在C++11及之后的版本)。class Shape {
public:
virtual void draw() = 0; // 纯虚函数,声明在C++98
// 或者
virtual void resize() = delete; // 声明在C++11,不允许重写
virtual ~Shape() {} // 虚析构函数
};
class Animal {
public:
virtual void makeSound() = 0; // 纯虚函数
};
class Dog : public Animal {
public:
void makeSound() override { std::cout << "Woof!" << std::endl; }
};
int main() {
// Animal animal; // 错误:Animal是抽象类,不能实例化
Dog dog;
dog.makeSound(); // 正确:调用Dog类的makeSound方法
return 0;
}
纯虚函数和抽象类是面向对象编程中实现接口规范和设计灵活性的重要工具。通过使用纯虚函数,可以定义一个必须由派生类实现的接口,而抽象类则提供了一种机制,确保类作为接口存在,不被直接实例化。这有助于构建清晰、可维护的软件架构。
#include
。cin
和cout
进行输入输出操作。const
定义符号常量,代替#define
。以下是一个C++程序的样例代码,以及对代码架构的解释:
// Example.cpp
#include // 4. 预处理指令,包含标准输入输出流库
// 3. 使用const定义符号常量,代替#define
const double PI = 3.14159;
// 5. 函数定义和声明
// 声明一个函数,该函数计算圆的面积
double calculateCircleArea(double radius);
// 1. 初识C++程序
// 主函数是每个C++程序的入口点
int main() {
// 2. 使用cin和cout进行输入输出操作
std::cout << "Enter the radius of the circle: ";
double radius;
std::cin >> radius;
// 调用函数并显示结果
double area = calculateCircleArea(radius);
std::cout << "The area of the circle is: " << area << std::endl;
return 0;
}
// 5. 函数定义
// 定义前面声明的函数,计算并返回圆的面积
double calculateCircleArea(double radius) {
return PI * radius * radius; // 使用符号常量PI
}
预处理器指令 (#include
):
std::cout
和std::cin
。符号常量定义 (const double PI = 3.14159;
):
const
关键字定义了一个符号常量PI
,它用于存储圆周率的值。这比宏定义(#define
)更好,因为它有数据类型,编译器会在编译时检查类型安全。函数的声明 (double calculateCircleArea(double radius);
):
main
函数之前声明了calculateCircleArea
函数,这允许我们在main
函数中调用它,尽管它在后面才被定义。主函数 (int main() { ... }
):
main
函数是程序的入口点。程序执行从这里开始。输入输出操作 (std::cout
和 std::cin
):
std::cout
输出提示信息到控制台,使用std::cin
从控制台读取用户输入的半径值。函数调用 (double area = calculateCircleArea(radius);
):
main
函数中调用了之前声明的calculateCircleArea
函数,并使用返回的面积值。函数定义 (double calculateCircleArea(double radius) { ... }
):
calculateCircleArea
函数的定义,它计算并返回圆的面积。函数体内使用了之前定义的PI
常量。这个样例程序展示了C++程序的基本结构,包括预处理指令的使用、符号常量的声明、函数的声明与定义,以及输入输出操作。通过这个样例,您可以了解如何编写一个简单的C++程序,并逐步扩展更复杂的逻辑。
以下是一个C++程序样例,它涵盖了值传递形参、引用传递形参以及带默认形参值的函数的知识点,并提供了代码架构的解释:
#include
using namespace std;
// 函数示例1:值传递
void valuePassing(int n) {
n += 10; // 修改n的值,但不会影响实参
}
// 函数示例2:引用传递
void referencePassing(int &r) {
r += 20; // 通过引用修改实参的值
}
// 函数示例3:带默认参数值的函数
void printMessage(const string &msg, const string &appender = "!") {
cout << msg << appender << endl;
}
int main() {
int a = 5;
string greeting = "Hello";
// 演示值传递
cout << "Value passing before: " << a << endl;
valuePassing(a);
cout << "Value passing after: " << a << endl; // a的值不变
// 演示引用传递
cout << "Reference passing before: " << a << endl;
referencePassing(a);
cout << "Reference passing after: " << a << endl; // a的值改变
// 演示带默认参数值的函数
printMessage(greeting); // 使用默认的附加字符串
printMessage(greeting, "!!!"); // 使用自定义的附加字符串
return 0;
}
值传递函数 (valuePassing
):
int
类型的参数n
,通过值传递的方式。函数内部对n
的修改不会影响到实参。引用传递函数 (referencePassing
):
int
类型的引用参数r
,通过引用传递的方式。函数内部对r
的修改会影响到实参。带默认参数值的函数 (printMessage
):
string
类型的参数,其中第二个参数appender
有默认值"!"
。如果调用时不提供第二个参数,将使用默认值。main
函数:
a
和greeting
,用于演示值传递和引用传递的效果。valuePassing
函数展示值传递,调用referencePassing
函数展示引用传递。printMessage
函数两次,一次使用默认参数,一次使用自定义参数。输入输出 (cout
):
cout
来显示变量的值变化和消息。这个样例程序清晰地展示了值传递和引用传递的区别,以及如何为函数参数设置默认值。通过运行这个程序,您可以直观地看到每种传递方式对实参的影响。
以下是一个C++程序样例,它涵盖了类的定义和对象的使用,并提供了代码架构的解释:
#include
using namespace std;
// 10. 类的定义
// 定义一个简单的类Person
class Person {
private:
string name; // 私有成员变量,存储人的名字
int age; // 私有成员变量,存储人的年龄
public:
// 类的构造函数
Person(const string& name, int age) : name(name), age(age) {}
// 成员函数,用于输出Person的信息
void displayInfo() const {
cout << "Name: " << name << ", Age: " << age << endl;
}
// 成员函数,用于设置Person的名字
void setName(const string& newName) {
name = newName;
}
// 成员函数,用于设置Person的年龄
void setAge(int newAge) {
age = newAge;
}
};
// 11. 对象的定义与使用
int main() {
// 定义Person类的对象
Person person1("Alice", 30); // 使用构造函数创建对象
// 使用成员函数displayInfo输出对象信息
person1.displayInfo();
// 改变对象的状态
person1.setName("Bob");
person1.setAge(25);
// 再次使用成员函数displayInfo输出更新后的对象信息
person1.displayInfo();
return 0;
}
类的定义 (class Person
):
Person
的类,包含私有成员变量name
和age
,以及公共成员函数。构造函数 (Person(const string& name, int age)
):
Person
类的构造函数,用于初始化对象的name
和age
。成员函数 (displayInfo
, setName
, setAge
):
displayInfo
:输出Person的信息。setName
:设置Person的名字。setAge
:设置Person的年龄。main
函数:
Person
类的对象person1
,并使用构造函数初始化。displayInfo
成员函数来显示person1
的信息。setName
和setAge
成员函数来更新person1
的状态。displayInfo
来显示更新后的信息。对象的定义与使用:
person1
是Person
类的一个对象实例,展示了如何创建和使用类的对象。这个样例程序展示了如何在C++中定义一个类,以及如何创建和操作类的对象。通过这个程序,您可以学习到类的基本结构、成员变量、构造函数以及成员函数的使用。
以下是一个C++程序样例,它涵盖了构造函数、复制构造函数以及构造函数的初始化列表的使用,并提供了代码架构的解释:
#include
using namespace std;
// 定义一个简单的类Box,表示一个立方体盒子
class Box {
private:
double length; // 长度
double width; // 宽度
double height; // 高度
public:
// 12. 构造函数
// 使用初始化列表对成员变量进行初始化
Box(double l = 1.0, double w = 1.0, double h = 1.0)
: length(l), width(w), height(h) {
cout << "Box constructed with length " << length
<< ", width " << width << ", and height " << height << endl;
}
// 复制构造函数
Box(const Box& other)
: length(other.length), width(other.width), height(other.height) {
cout << "Copy constructor called." << endl;
}
// 成员函数,用于输出盒子的尺寸
void displayDimensions() const {
cout << "Box dimensions: length = " << length
<< ", width = " << width << ", height = " << height << endl;
}
};
int main() {
// 使用默认参数创建一个Box对象
Box box1(2.0, 3.0, 4.0);
box1.displayDimensions();
// 使用复制构造函数创建box1的副本
Box box2 = box1; // 调用复制构造函数
box2.displayDimensions();
return 0;
}
类定义 (class Box
):
Box
的类,包含私有成员变量length
、width
和height
。构造函数 (Box(double l = 1.0, double w = 1.0, double h = 1.0)
):
Box
类的构造函数,使用默认参数和初始化列表对成员变量进行初始化,并输出构造时的信息。复制构造函数 (Box(const Box& other)
):
Box
类的复制构造函数,使用初始化列表复制另一个Box
对象的成员变量,并输出复制构造函数被调用的信息。成员函数 (displayDimensions
):
main
函数:
Box
类的对象box1
,并显示其尺寸。box1
的副本box2
,并显示其尺寸。对象的创建和复制:
box1
是直接使用构造函数创建的,而box2
是通过复制构造函数从box1
复制得到的。这个样例程序展示了构造函数和复制构造函数的使用,以及如何利用构造函数的初始化列表来初始化对象的成员变量。通过运行这个程序,您可以直观地看到构造函数和复制构造函数的调用和它们的作用。
using
声明和using namespace
指令。以下是一个C++程序样例,它涵盖了前向引用声明、命名空间的使用以及静态成员的概念,并提供了代码架构的解释:
#include
using namespace std;
// 15. 命名空间的使用
namespace MyNamespace {
class MyClass; // 14. 前向引用声明
class MyOtherClass {
public:
void display() {
cout << "MyOtherClass display function." << endl;
}
};
}
class MyClass {
public:
void display() {
cout << "MyClass display function." << endl;
}
// 16. 静态成员变量
static int count;
// 16. 静态成员函数
static void staticFunction() {
cout << "Static function in MyClass." << endl;
}
};
// 16. 静态成员变量的定义
int MyClass::count = 0;
void useMyClasses() {
MyNamespace::MyOtherClass other;
MyClass myClass;
other.display();
myClass.display();
cout << "MyClass object count: " << MyClass::count << endl; // 16. 使用静态成员变量
MyClass::staticFunction(); // 16. 调用静态成员函数
}
int main() {
// 使用using声明来使用MyNamespace中的MyClass和MyOtherClass
using MyNamespace::MyClass;
using MyNamespace::MyOtherClass;
MyClass myClassInstance;
MyOtherClass otherClassInstance;
myClassInstance.display();
otherClassInstance.display();
useMyClasses();
return 0;
}
命名空间声明 (namespace MyNamespace
):
MyNamespace
,用于封装类MyClass
和MyOtherClass
。前向引用声明 (class MyClass;
):
MyNamespace
命名空间中提前声明了MyClass
类,这是一个前向引用声明。类定义 (class MyClass
和 class MyOtherClass
):
MyClass
和MyOtherClass
两个类,包含成员函数display
用于输出信息。静态成员变量 (static int count
):
MyClass
中定义了一个静态成员变量count
,用于跟踪MyClass
对象的数量。静态成员函数 (static void staticFunction()
):
MyClass
中定义了一个静态成员函数staticFunction
,可以被类直接调用而不需要对象实例。静态成员变量的定义 (int MyClass::count = 0;
):
count
提供了定义和初始化。使用using声明 (using MyNamespace::MyClass; using MyNamespace::MyOtherClass;
):
main
函数中使用using
声明来引入MyNamespace
命名空间中的MyClass
和MyOtherClass
,使得可以直接使用这些类而不需要命名空间前缀。main
函数:
MyClass
和MyOtherClass
的对象,并调用它们的display
成员函数。useMyClasses
函数,演示了如何使用静态成员变量和静态成员函数。useMyClasses
函数:
这个样例程序展示了如何在C++中使用命名空间来组织代码,如何进行前向引用声明,以及静态成员的使用。通过这个程序,您可以学习到如何在实际编程中应用这些概念。
以下是一个C++程序样例,它涵盖了友元函数和常成员函数的概念,并提供了代码架构的解释:
#include
using namespace std;
// 定义一个简单的类Box
class Box {
private:
int length;
int width;
int height;
public:
// 构造函数
Box(int l, int w, int h) : length(l), width(w), height(h) {}
// 18. 常成员函数:getVolume
// 这个函数被声明为const,意味着它不会修改对象的状态
int getVolume() const {
return length * width * height;
}
// 声明友元函数
friend int getSurfaceArea(const Box&);
};
// 17. 友元函数:getSurfaceArea
// 这个函数不是Box类的成员函数,但可以访问Box类的私有成员
int getSurfaceArea(const Box& box) {
return 2 * (box.length * box.width + box.width * box.height + box.height * box.length);
}
int main() {
Box box(10, 20, 30); // 创建Box对象
// 调用常成员函数getVolume
cout << "Volume of the box: " << box.getVolume() << endl;
// 友元函数getSurfaceArea可以访问box的私有成员
cout << "Surface area of the box: " << getSurfaceArea(box) << endl;
return 0;
}
类定义 (class Box
):
Box
的类,包含私有成员变量length
、width
和height
。构造函数 (Box(int l, int w, int h)
):
Box
类的构造函数,用于初始化对象的尺寸。常成员函数 (int getVolume() const
):
getVolume
函数被声明为const
,表示它是一个常成员函数,不会修改对象的状态。它计算并返回盒子的体积。友元函数声明:
Box
类中,使用friend
关键字声明getSurfaceArea
函数为友元函数,允许它访问Box
类的私有成员。友元函数定义 (int getSurfaceArea(const Box& box)
):
getSurfaceArea
函数计算并返回盒子的表面积。尽管它不是Box
类的成员函数,但由于被声明为友元,它可以访问Box
类的私有成员。main
函数:
Box
类的对象box
。getVolume
常成员函数来获取并输出盒子的体积。getSurfaceArea
来获取并输出盒子的表面积。友元函数的使用:
main
函数中,通过getSurfaceArea(box)
调用友元函数,展示了友元函数如何与类的对象交互,即使它不是类的成员函数。这个样例程序展示了如何在C++中使用友元函数来访问类的私有成员,以及如何定义和使用常成员函数。通过这个程序,您可以学习到友元函数和常成员函数在实际编程中的应用。
this
this
指针,展示它如何指向当前对象。以下是一个C++程序样例,它涵盖了对象指针、this
指针以及指向类成员的指针的使用,并提供了代码架构的解释:
#include
using namespace std;
// 定义一个简单的类Person
class Person {
private:
string name;
int age;
public:
// 构造函数
Person(const string& nm, int ag) : name(nm), age(ag) {}
// 使用this指针展示数据成员的初始值
void showInitialInfo() {
cout << "Name: " << this->name << ", Age: " << this->age << endl;
}
// 成员函数,使用对象指针操作数据成员
void introduce(Person* p) {
cout << "I am " << p->name << ", and I am " << p->age << " years old." << endl;
}
// 指向数据成员的指针
string* getNamePtr() { return &this->name; }
int* getAgePtr() { return &this->age; }
// 指向成员函数的指针
using FunPtr = void (Person::*)(const string&, int);
FunPtr getMemberFuncPtr() {
return &Person::setNameAndAge;
}
void setNameAndAge(const string& newName, int newAge) {
name = newName;
age = newAge;
cout << "Name and age updated to: " << name << ", " << age << endl;
}
};
int main() {
Person person("Alice", 30);
// 使用对象指针调用成员函数
person.introduce(&person);
// 使用this指针
person.showInitialInfo();
// 使用指向成员的指针
string* namePtr = person.getNamePtr();
int* agePtr = person.getAgePtr();
cout << "Name ptr: " << *namePtr << ", Age ptr: " << *agePtr << endl;
// 使用指向成员函数的指针
Person::FunPtr funcPtr = person.getMemberFuncPtr();
(person.*funcPtr)("Bob", 25); // 使用成员函数指针调用成员函数
return 0;
}
类定义 (class Person
):
Person
的类,包含私有数据成员name
和age
,以及多个成员函数。构造函数 (Person(const string& nm, int ag)
):
Person
类的构造函数,用于初始化对象的名称和年龄。成员函数 (showInitialInfo
, introduce
, getNamePtr
, getAgePtr
, getMemberFuncPtr
, setNameAndAge
):
showInitialInfo
:展示使用this
指针访问数据成员的初始值。introduce
:使用对象指针p
来访问和操作另一个Person
对象的数据成员。getNamePtr
和 getAgePtr
:返回指向数据成员的指针。getMemberFuncPtr
:返回指向成员函数setNameAndAge
的指针。main
函数:
Person
类的对象person
。introduce
成员函数和对象指针来操作对象。showInitialInfo
成员函数,展示this
指针的使用。getNamePtr
和getAgePtr
获取指向数据成员的指针,并输出成员值。getMemberFuncPtr
获取指向成员函数的指针,并调用该成员函数。对象指针的使用:
main
函数中,通过&person
获取对象的地址,并将其作为对象指针传递给introduce
成员函数。this
指针的使用:
showInitialInfo
成员函数中,使用this->name
和this->age
来访问当前对象的数据成员。指向成员的指针:
getNamePtr
和getAgePtr
成员函数返回指向私有数据成员的指针。getMemberFuncPtr
返回一个指向成员函数的指针,然后通过这种指针调用成员函数。这个样例程序展示了对象指针、this
指针以及指向类成员的指针的使用。通过这个程序,您可以学习到如何在C++中操作和管理类的对象,以及如何使用指针来提高程序的灵活性。
以下是一个C++程序样例,它涵盖了继承方式、类型兼容规则以及派生类的构造和析构函数的概念,并提供了代码架构的解释:
#include
using namespace std;
// 基类 Shape
class Shape {
public:
// 构造函数
Shape() {
cout << "Shape constructor called." << endl;
}
// 虚析构函数
virtual ~Shape() {
cout << "Shape destructor called." << endl;
}
// 虚函数,用于多态
virtual void draw() {
cout << "Drawing a shape." << endl;
}
};
// 派生类 Circle,单继承自 Shape
class Circle : public Shape {
public:
// 构造函数
Circle() {
cout << "Circle constructor called." << endl;
}
// 重写析构函数
~Circle() {
cout << "Circle destructor called." << endl;
}
// 重写虚函数 draw
void draw() override {
cout << "Drawing a circle." << endl;
}
};
// 派生类 Square,单继承自 Shape
class Square : public Shape {
public:
// 构造函数
Square() {
cout << "Square constructor called." << endl;
}
// 析构函数
~Square() {
cout << "Square destructor called." << endl;
}
// 重写虚函数 draw
void draw() override {
cout << "Drawing a square." << endl;
}
};
// 多继承示例
class CircleSquare : public Circle, public Square {
public:
CircleSquare() {
cout << "CircleSquare constructor called." << endl;
}
~CircleSquare() {
cout << "CircleSquare destructor called." << endl;
}
};
int main() {
// 使用基类指针操作派生类对象,展示类型兼容规则
Shape* shape = new Circle(); // 向上转型
shape->draw(); // 多态行为,调用 Circle::draw
delete shape; // 调用 Circle 的析构函数
shape = new Square(); // 再次向上转型
shape->draw(); // 调用 Square::draw
delete shape; // 调用 Square 的析构函数
// 多继承示例
CircleSquare* cSquare = new CircleSquare();
cSquare->draw(); // 多态行为,调用 CircleSquare 的 draw
delete cSquare; // 调用 CircleSquare 的析构函数
return 0;
}
基类 Shape:
Shape
的基类,包含构造函数、虚析构函数和虚函数 draw
。派生类 Circle 和 Square:
Shape
基类单继承的派生类 Circle
和 Square
。每个类都有自己的构造函数和析构函数,并重写了 draw
函数。多继承示例 CircleSquare:
CircleSquare
的类,它同时继承自 Circle
和 Square
类,展示了多继承的概念。main
函数:
Shape
类型的指针 shape
,并通过这个指针操作 Circle
和 Square
对象,展示了类型兼容规则。draw
函数,展示了多态行为。CircleSquare
对象并调用其 draw
函数,展示了多继承的使用。构造函数和析构函数的执行:
这个样例程序展示了如何在C++中使用继承和多态,以及如何通过基类指针操作派生类对象。通过这个程序,您可以学习到继承方式、类型兼容规则以及派生类的构造和析构函数的执行机制。
以下是一个C++程序样例,它涵盖了虚基类和动态联编的概念,并提供了代码架构的解释:
#include
using namespace std;
// 定义一个基类 Shape,声明为虚基类
class Shape {
public:
virtual void draw() { cout << "Drawing a shape." << endl; }
virtual ~Shape() {}
};
// 派生类 Circle,继承自虚基类 Shape
class Circle : public virtual Shape {
public:
void draw() override {
cout << "Drawing a circle." << endl;
}
};
// 派生类 Square,继承自虚基类 Shape
class Square : public virtual Shape {
public:
void draw() override {
cout << "Drawing a square." << endl;
}
};
// 多重继承类 PolyShape,同时继承自 Circle 和 Square
class PolyShape : public Circle, public Square {
public:
void draw() override {
cout << "Drawing a complex shape made of circles and squares." << endl;
}
};
int main() {
// 使用基类指针指向派生类对象,展示多态
Shape* shape = new PolyShape();
shape->draw(); // 动态联编调用 PolyShape::draw
delete shape; // 正确调用析构函数
return 0;
}
虚基类 Shape:
Shape
的基类,并声明其为虚基类。包含一个虚函数 draw
和虚析构函数。派生类 Circle 和 Square:
Shape
虚基类派生的类 Circle
和 Square
。每个类都重写了 draw
函数。多重继承类 PolyShape:
PolyShape
的类,它同时继承自 Circle
和 Square
。展示了多继承的情况,并重写了 draw
函数。main
函数:
Shape
类型的指针 shape
,并通过这个指针操作 PolyShape
对象。shape->draw()
展示了多态性,即使 shape
是基类类型的指针,它也能调用正确的 PolyShape::draw
函数。动态联编:
析构函数的调用:
main
函数的末尾,删除 shape
指针指向的对象时,会按照构造的逆序调用析构函数,首先调用 PolyShape
的析构函数,然后是 Circle
和 Square
的析构函数,最后调用 Shape
的析构函数。这个样例程序展示了如何在C++中使用虚基类来避免多继承中的二义性问题,以及如何通过虚函数实现多态性。通过运行这个程序,您可以直观地看到多态的工作原理和析构函数的正确调用顺序。